Repository: rust-analyzer/rust-analyzer
Pull request #1815 (2019-09-11 14:34:42)

Support correct `$crate` expansion in macros
This PR makes normal use cases of `$crate` from macros work as expected.

It makes more macros from `std` work. Type inference works well with `panic`, `unimplemented`, `format`, and maybe more.
Sadly that `vec![1, 2, 3]` still not works, but it is not longer an issue about macro.

Screenshot:
![Screenshot_20190927_022136](https://user-images.githubusercontent.com/14816024/65714465-b4568f80-e0cd-11e9-8043-dd44c2ae8040.png)




uHOOCCOOHu: @matklad
> ..., but, when we lower ast to paths, we make sure to convert $crate to a Repr::DollarCrate with the appropriate crate id.

Do you mean we need to pass `CrateId` through `parse_or_expand` [here](https://github.com/rust-analyzer/rust-analyzer/pull/1815/files#diff-51cf0d02787e805fff19a8238d651d8eR464)? But all `MacroCall` must do this replacement and it will become kind of redundant.

Well, in fact, I don't know how to get this information in `ast::Name::as_name` without passing it through `SyntaxToken::text`.

matklad: In general, it seems like any call to `Path::from_ast` should gain an additional parameter, the file where the pat resides, such that `Path::from_ast` can figure out the meaning of the `$crate` if the file comes from macro expansion
uHOOCCOOHu: > In general, it seems like any call to Path::from_ast should gain an additional parameter, the file where the pat resides, such that Path::from_ast can figure out the meaning of the $crate if the file comes from macro expansion

Oops, since `Path::from_ast` is called from macro caller's context, the `current_file_id` will not be the crate containing `macro_rules` if it's a external macro.
If we lose this information in AST, we could never recover it in higher level.

matklad: `current_file_id` is the `HirFileId`. For macro files, it is `MacroFile`, which contains a `MacroCallId`, which contains `MacroDefId`, and the crate of this `MacroDefId` is the crate we need. 

That is, we identify macro calls by *both* the location of the call to the macro and the definition of the macro, and we can fetch the correct crate from the definition.
matklad: (we'd still need to add a `Crate` to `MacroDefId`)
uHOOCCOOHu: @matklad
I found in rustc, expansion of `$crate` is a single `tt`,  `stringify!` it results in `"$crate"` (no space inside), and passing it through macros to construct `use crate::$crate` will result in `no '$crate' in the root`.
It seems weird but just behaves the same as your design. :laughing: 

matklad: Note that for hygiene we'll have to augment AST itself with additional info, but I hope not to embedd the info direclty into the AST, and instead store it on the side.

Specifically, mbe tarnsform TokenTrees, and tokens in tts have identity. So, it is possible to correlate input tokens with output tokens. When we parse the token stream into AST, we should take care to "color" each identifier as comming from the macro argument, or from the macro expansion, using this info. But we'll store colors alongside the tree, as `FxHashMap<TextRange, ExpansionId>`.


uHOOCCOOHu: > `current_file_id` is the `HirFileId`. For macro files, it is `MacroFile`, which contains a `MacroCallId`, which contains `MacroDefId`, and the crate of this `MacroDefId` is the crate we need.
> 
> That is, we identify macro calls by _both_ the location of the call to the macro and the definition of the macro, and we can fetch the correct crate from the definition.

I'm trying it, but seems it cause tons of modification. Including `Path::from_ast`, `Generic::{from_ast,fill_params}`, some methods in `RawItemsCollector`, `SourceAnalyzer` and `TypeRef`, and more.
I'm curios that if it is the right way to do this. The code to parse paths are everywhere. 

For hygiene, note that identifiers are colored by the macro call id. And the color of identifier is only used in expression or statement place. Items defined by macros can always escape.

Will it be easier to use hygiene for `$crate`?

matklad: I believe that, to support hygiene, there's no way around changing every call-site where we convert AST to hir. An isolated `ast::Path` is fundamentally a lossy type, which doesn't have affordance for hygiene. 

But I'll be fine with doing this incrementally: instead of changing `from_ast`, introduce a `from_ast_with_hygiene` method alongside, and leisurely remove usages of the former, polishing the API along the way.

However, I think we've recently distilled a good abstraction to help with is: `ast::Whatever` is a value-type ast. Two textually equal whatevers in two different files can be represented by a single ast node (ast is ref-counted inside). And `Source<ast::Whatever>` is a specific *instance* of `ast::Whatever`, which is an AstValue plus associated identity (HirFileId). So, I think we need

```rust
impl Path {
    fn from_src(src: Source<ast::Path>)
}
```

>Will it be easier to use hygiene for $crate?

I think now, as I imagine hyginee looking as `DB::hygiene_info(file_id: HirFileId) -> FxHashMap<TextRange, HirFIleId>`. Ie, you still need to thread `HirFileId`, but you have a new db query on top!.
matklad: @uHOOCCOOHu do you plan to follow up here? I am extremely excited about this, as figuring out hygiene is one of the few yet unresolved questions in rust-analyzer's architecture!
uHOOCCOOHu: @matklad 
Oh, just kind of busy recently. I'll look into this later this week.

I'm not planning to support full featured hygienic macro here,  though `$crate` can be a part of it.


Patch:
diff --git a/crates/ra_assists/src/assists/auto_import.rs b/crates/ra_assists/src/assists/auto_import.rs
index 5aae985461..43c14ad238 100644
--- a/crates/ra_assists/src/assists/auto_import.rs
+++ b/crates/ra_assists/src/assists/auto_import.rs
@@ -512,7 +512,7 @@ pub fn collect_hir_path_segments(path: &hir::Path) -> Option<Vec<SmolStr>> {
         hir::PathKind::Plain => {}
         hir::PathKind::Self_ => ps.push("self".into()),
         hir::PathKind::Super => ps.push("super".into()),
-        hir::PathKind::Type(_) => return None,
+        hir::PathKind::Type(_) | hir::PathKind::DollarCrate(_) => return None,
     }
     for s in path.segments.iter() {
         ps.push(s.name.to_string().into());
diff --git a/crates/ra_hir/src/adt.rs b/crates/ra_hir/src/adt.rs
index fbb4ff4d84..99d2862150 100644
--- a/crates/ra_hir/src/adt.rs
+++ b/crates/ra_hir/src/adt.rs
@@ -133,7 +133,7 @@ impl VariantData {
                     .fields()
                     .enumerate()
                     .map(|(i, fd)| StructFieldData {
-                        name: Name::tuple_field_name(i),
+                        name: Name::new_tuple_field(i),
                         type_ref: TypeRef::from_ast_opt(fd.type_ref()),
                     })
                     .collect();
diff --git a/crates/ra_hir/src/code_model/src.rs b/crates/ra_hir/src/code_model/src.rs
index c0cb27b477..dc964e1566 100644
--- a/crates/ra_hir/src/code_model/src.rs
+++ b/crates/ra_hir/src/code_model/src.rs
@@ -119,7 +119,7 @@ impl HasSource for TypeAlias {
 impl HasSource for MacroDef {
     type Ast = ast::MacroCall;
     fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::MacroCall> {
-        Source { file_id: self.id.0.file_id(), ast: self.id.0.to_node(db) }
+        Source { file_id: self.id.ast_id.file_id(), ast: self.id.ast_id.to_node(db) }
     }
 }
 
diff --git a/crates/ra_hir/src/expr/lower.rs b/crates/ra_hir/src/expr/lower.rs
index 61535d24fe..6d6f605065 100644
--- a/crates/ra_hir/src/expr/lower.rs
+++ b/crates/ra_hir/src/expr/lower.rs
@@ -272,8 +272,11 @@ where
                 self.alloc_expr(Expr::Match { expr, arms }, syntax_ptr)
             }
             ast::Expr::PathExpr(e) => {
-                let path =
-                    e.path().and_then(Path::from_ast).map(Expr::Path).unwrap_or(Expr::Missing);
+                let path = e
+                    .path()
+                    .and_then(|path| self.parse_path(path))
+                    .map(Expr::Path)
+                    .unwrap_or(Expr::Missing);
                 self.alloc_expr(path, syntax_ptr)
             }
             ast::Expr::ContinueExpr(_e) => {
@@ -295,7 +298,7 @@ where
                 self.alloc_expr(Expr::Return { expr }, syntax_ptr)
             }
             ast::Expr::RecordLit(e) => {
-                let path = e.path().and_then(Path::from_ast);
+                let path = e.path().and_then(|path| self.parse_path(path));
                 let mut field_ptrs = Vec::new();
                 let record_lit = if let Some(nfl) = e.record_field_list() {
                     let fields = nfl
@@ -459,7 +462,7 @@ where
                     .ast_id(&e)
                     .with_file_id(self.current_file_id);
 
-                if let Some(path) = e.path().and_then(Path::from_ast) {
+                if let Some(path) = e.path().and_then(|path| self.parse_path(path)) {
                     if let Some(def) = self.resolver.resolve_path_as_macro(self.db, &path) {
                         let call_id = MacroCallLoc { def: def.id, ast_id }.id(self.db);
                         let file_id = call_id.as_file(MacroFileKind::Expr);
@@ -529,7 +532,7 @@ where
                 Pat::Bind { name, mode: annotation, subpat }
             }
             ast::Pat::TupleStructPat(p) => {
-                let path = p.path().and_then(Path::from_ast);
+                let path = p.path().and_then(|path| self.parse_path(path));
                 let args = p.args().map(|p| self.collect_pat(p)).collect();
                 Pat::TupleStruct { path, args }
             }
@@ -539,7 +542,7 @@ where
                 Pat::Ref { pat, mutability }
             }
             ast::Pat::PathPat(p) => {
-                let path = p.path().and_then(Path::from_ast);
+                let path = p.path().and_then(|path| self.parse_path(path));
                 path.map(Pat::Path).unwrap_or(Pat::Missing)
             }
             ast::Pat::TuplePat(p) => {
@@ -548,7 +551,7 @@ where
             }
             ast::Pat::PlaceholderPat(_) => Pat::Wild,
             ast::Pat::RecordPat(p) => {
-                let path = p.path().and_then(Path::from_ast);
+                let path = p.path().and_then(|path| self.parse_path(path));
                 let record_field_pat_list =
                     p.record_field_pat_list().expect("every struct should have a field list");
                 let mut fields: Vec<_> = record_field_pat_list
@@ -589,6 +592,10 @@ where
             self.missing_pat()
         }
     }
+
+    fn parse_path(&mut self, path: ast::Path) -> Option<Path> {
+        Path::from_src(Source { ast: path, file_id: self.current_file_id }, self.db)
+    }
 }
 
 impl From<ast::BinOp> for BinaryOp {
diff --git a/crates/ra_hir/src/generics.rs b/crates/ra_hir/src/generics.rs
index 6865d34ba7..4ce7551c33 100644
--- a/crates/ra_hir/src/generics.rs
+++ b/crates/ra_hir/src/generics.rs
@@ -132,6 +132,7 @@ impl GenericParams {
     fn fill_params(&mut self, params: ast::TypeParamList, start: u32) {
         for (idx, type_param) in params.type_params().enumerate() {
             let name = type_param.name().map_or_else(Name::missing, |it| it.as_name());
+            // FIXME: Use `Path::from_src`
             let default = type_param.default_type().and_then(|t| t.path()).and_then(Path::from_ast);
 
             let param = GenericParam { idx: idx as u32 + start, name: name.clone(), default };
diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs
index 9ea4e695d9..bcbcd3dd77 100644
--- a/crates/ra_hir/src/ids.rs
+++ b/crates/ra_hir/src/ids.rs
@@ -10,7 +10,7 @@ use ra_syntax::{ast, AstNode, Parse, SyntaxNode};
 
 use crate::{
     db::{AstDatabase, DefDatabase, InternDatabase},
-    AstId, FileAstId, Module, Source,
+    AstId, Crate, FileAstId, Module, Source,
 };
 
 /// hir makes heavy use of ids: integer (u32) handlers to various things. You
@@ -58,6 +58,17 @@ impl HirFileId {
         }
     }
 
+    /// Get the crate which the macro lives in, if it is a macro file.
+    pub(crate) fn macro_crate(self, db: &impl AstDatabase) -> Option<Crate> {
+        match self.0 {
+            HirFileIdRepr::File(_) => None,
+            HirFileIdRepr::Macro(macro_file) => {
+                let loc = macro_file.macro_call_id.loc(db);
+                Some(loc.def.krate)
+            }
+        }
+    }
+
     pub(crate) fn parse_or_expand_query(
         db: &impl AstDatabase,
         file_id: HirFileId,
@@ -121,10 +132,13 @@ impl From<FileId> for HirFileId {
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub struct MacroDefId(pub(crate) AstId<ast::MacroCall>);
+pub struct MacroDefId {
+    pub(crate) ast_id: AstId<ast::MacroCall>,
+    pub(crate) krate: Crate,
+}
 
 pub(crate) fn macro_def_query(db: &impl AstDatabase, id: MacroDefId) -> Option<Arc<MacroRules>> {
-    let macro_call = id.0.to_node(db);
+    let macro_call = id.ast_id.to_node(db);
     let arg = macro_call.token_tree()?;
     let (tt, _) = mbe::ast_to_token_tree(&arg).or_else(|| {
         log::warn!("fail on macro_def to token tree: {:#?}", arg);
diff --git a/crates/ra_hir/src/impl_block.rs b/crates/ra_hir/src/impl_block.rs
index d830202bd2..c66a1c6a6d 100644
--- a/crates/ra_hir/src/impl_block.rs
+++ b/crates/ra_hir/src/impl_block.rs
@@ -218,7 +218,10 @@ impl ModuleImplBlocks {
                 ast::ItemOrMacro::Macro(macro_call) => {
                     //FIXME: we should really cut down on the boilerplate required to process a macro
                     let ast_id = db.ast_id_map(file_id).ast_id(&macro_call).with_file_id(file_id);
-                    if let Some(path) = macro_call.path().and_then(Path::from_ast) {
+                    if let Some(path) = macro_call
+                        .path()
+                        .and_then(|path| Path::from_src(Source { ast: path, file_id }, db))
+                    {
                         if let Some(def) = self.module.resolver(db).resolve_path_as_macro(db, &path)
                         {
                             let call_id = MacroCallLoc { def: def.id, ast_id }.id(db);
diff --git a/crates/ra_hir/src/marks.rs b/crates/ra_hir/src/marks.rs
index b2111be053..72f76bb797 100644
--- a/crates/ra_hir/src/marks.rs
+++ b/crates/ra_hir/src/marks.rs
@@ -14,4 +14,6 @@ test_utils::marks!(
     macro_rules_from_other_crates_are_visible_with_macro_use
     prelude_is_macro_use
     coerce_merge_fail_fallback
+    macro_dollar_crate_self
+    macro_dollar_crate_other
 );
diff --git a/crates/ra_hir/src/name.rs b/crates/ra_hir/src/name.rs
index 1bf993ffb0..d50867f5dc 100644
--- a/crates/ra_hir/src/name.rs
+++ b/crates/ra_hir/src/name.rs
@@ -5,20 +5,21 @@ use ra_syntax::{ast, SmolStr};
 /// `Name` is a wrapper around string, which is used in hir for both references
 /// and declarations. In theory, names should also carry hygiene info, but we are
 /// not there yet!
-#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
-pub struct Name {
-    text: SmolStr,
-}
+#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
+pub struct Name(Repr);
 
-impl fmt::Display for Name {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        fmt::Display::fmt(&self.text, f)
-    }
+#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
+enum Repr {
+    Text(SmolStr),
+    TupleField(usize),
 }
 
-impl fmt::Debug for Name {
+impl fmt::Display for Name {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        fmt::Debug::fmt(&self.text, f)
+        match &self.0 {
+            Repr::Text(text) => fmt::Display::fmt(&text, f),
+            Repr::TupleField(idx) => fmt::Display::fmt(&idx, f),
+        }
     }
 }
 
@@ -26,29 +27,38 @@ impl Name {
     /// Note: this is private to make creating name from random string hard.
     /// Hopefully, this should allow us to integrate hygiene cleaner in the
     /// future, and to switch to interned representation of names.
-    const fn new(text: SmolStr) -> Name {
-        Name { text }
+    const fn new_text(text: SmolStr) -> Name {
+        Name(Repr::Text(text))
     }
 
-    pub(crate) fn missing() -> Name {
-        Name::new("[missing name]".into())
+    pub(crate) fn new_tuple_field(idx: usize) -> Name {
+        Name(Repr::TupleField(idx))
     }
 
-    pub(crate) fn tuple_field_name(idx: usize) -> Name {
-        Name::new(idx.to_string().into())
+    /// 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))
     }
 
-    // There's should be no way to extract a string out of `Name`: `Name` in the
-    // future, `Name` will include hygiene information, and you can't encode
-    // hygiene into a String.
-    //
-    // If you need to compare something with `Name`, compare `Name`s directly.
-    //
-    // If you need to render `Name` for the user, use the `Display` impl, but be
-    // aware that it strips hygiene info.
-    #[deprecated(note = "use to_string instead")]
-    pub fn as_smolstr(&self) -> &SmolStr {
-        &self.text
+    /// Resolve a name from the text of token.
+    fn resolve(raw_text: &SmolStr) -> Name {
+        let raw_start = "r#";
+        if raw_text.as_str().starts_with(raw_start) {
+            Name::new_text(SmolStr::new(&raw_text[raw_start.len()..]))
+        } else {
+            Name::new_text(raw_text.clone())
+        }
+    }
+
+    pub(crate) fn missing() -> Name {
+        Name::new_text("[missing name]".into())
+    }
+
+    pub(crate) fn as_tuple_index(&self) -> Option<usize> {
+        match self.0 {
+            Repr::TupleField(idx) => Some(idx),
+            _ => None,
+        }
     }
 }
 
@@ -58,15 +68,16 @@ pub(crate) trait AsName {
 
 impl AsName for ast::NameRef {
     fn as_name(&self) -> Name {
-        let name = resolve_name(self.text());
-        Name::new(name)
+        match self.as_tuple_field() {
+            Some(idx) => Name::new_tuple_field(idx),
+            None => Name::resolve(self.text()),
+        }
     }
 }
 
 impl AsName for ast::Name {
     fn as_name(&self) -> Name {
-        let name = resolve_name(self.text());
-        Name::new(name)
+        Name::resolve(self.text())
     }
 }
 
@@ -74,66 +85,56 @@ impl AsName for ast::FieldKind {
     fn as_name(&self) -> Name {
         match self {
             ast::FieldKind::Name(nr) => nr.as_name(),
-            ast::FieldKind::Index(idx) => Name::new(idx.text().clone()),
+            ast::FieldKind::Index(idx) => Name::new_tuple_field(idx.text().parse().unwrap()),
         }
     }
 }
 
 impl AsName for ra_db::Dependency {
     fn as_name(&self) -> Name {
-        Name::new(self.name.clone())
+        Name::new_text(self.name.clone())
     }
 }
 
 // Primitives
-pub(crate) const ISIZE: Name = Name::new(SmolStr::new_inline_from_ascii(5, b"isize"));
-pub(crate) const I8: Name = Name::new(SmolStr::new_inline_from_ascii(2, b"i8"));
-pub(crate) const I16: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"i16"));
-pub(crate) const I32: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"i32"));
-pub(crate) const I64: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"i64"));
-pub(crate) const I128: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"i128"));
-pub(crate) const USIZE: Name = Name::new(SmolStr::new_inline_from_ascii(5, b"usize"));
-pub(crate) const U8: Name = Name::new(SmolStr::new_inline_from_ascii(2, b"u8"));
-pub(crate) const U16: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"u16"));
-pub(crate) const U32: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"u32"));
-pub(crate) const U64: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"u64"));
-pub(crate) const U128: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"u128"));
-pub(crate) const F32: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"f32"));
-pub(crate) const F64: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"f64"));
-pub(crate) const BOOL: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"bool"));
-pub(crate) const CHAR: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"char"));
-pub(crate) const STR: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"str"));
+pub(crate) const ISIZE: Name = Name::new_inline_ascii(5, b"isize");
+pub(crate) const I8: Name = Name::new_inline_ascii(2, b"i8");
+pub(crate) const I16: Name = Name::new_inline_ascii(3, b"i16");
+pub(crate) const I32: Name = Name::new_inline_ascii(3, b"i32");
+pub(crate) const I64: Name = Name::new_inline_ascii(3, b"i64");
+pub(crate) const I128: Name = Name::new_inline_ascii(4, b"i128");
+pub(crate) const USIZE: Name = Name::new_inline_ascii(5, b"usize");
+pub(crate) const U8: Name = Name::new_inline_ascii(2, b"u8");
+pub(crate) const U16: Name = Name::new_inline_ascii(3, b"u16");
+pub(crate) const U32: Name = Name::new_inline_ascii(3, b"u32");
+pub(crate) const U64: Name = Name::new_inline_ascii(3, b"u64");
+pub(crate) const U128: Name = Name::new_inline_ascii(4, b"u128");
+pub(crate) const F32: Name = Name::new_inline_ascii(3, b"f32");
+pub(crate) const F64: Name = Name::new_inline_ascii(3, b"f64");
+pub(crate) const BOOL: Name = Name::new_inline_ascii(4, b"bool");
+pub(crate) const CHAR: Name = Name::new_inline_ascii(4, b"char");
+pub(crate) const STR: Name = Name::new_inline_ascii(3, b"str");
 
 // Special names
-pub(crate) const SELF_PARAM: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"self"));
-pub(crate) const SELF_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"Self"));
-pub(crate) const MACRO_RULES: Name = Name::new(SmolStr::new_inline_from_ascii(11, b"macro_rules"));
+pub(crate) const SELF_PARAM: Name = Name::new_inline_ascii(4, b"self");
+pub(crate) const SELF_TYPE: Name = Name::new_inline_ascii(4, b"Self");
+pub(crate) const MACRO_RULES: Name = Name::new_inline_ascii(11, b"macro_rules");
 
 // Components of known path (value or mod name)
-pub(crate) const STD: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"std"));
-pub(crate) const ITER: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"iter"));
-pub(crate) const OPS: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"ops"));
-pub(crate) const FUTURE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"future"));
-pub(crate) const RESULT: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"result"));
-pub(crate) const BOXED: Name = Name::new(SmolStr::new_inline_from_ascii(5, b"boxed"));
+pub(crate) const STD: Name = Name::new_inline_ascii(3, b"std");
+pub(crate) const ITER: Name = Name::new_inline_ascii(4, b"iter");
+pub(crate) const OPS: Name = Name::new_inline_ascii(3, b"ops");
+pub(crate) const FUTURE: Name = Name::new_inline_ascii(6, b"future");
+pub(crate) const RESULT: Name = Name::new_inline_ascii(6, b"result");
+pub(crate) const BOXED: Name = Name::new_inline_ascii(5, b"boxed");
 
 // Components of known path (type name)
-pub(crate) const INTO_ITERATOR_TYPE: Name =
-    Name::new(SmolStr::new_inline_from_ascii(12, b"IntoIterator"));
-pub(crate) const ITEM_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"Item"));
-pub(crate) const TRY_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"Try"));
-pub(crate) const OK_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(2, b"Ok"));
-pub(crate) const FUTURE_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Future"));
-pub(crate) const RESULT_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Result"));
-pub(crate) const OUTPUT_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Output"));
-pub(crate) const TARGET_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Target"));
-pub(crate) const BOX_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"Box"));
-
-fn resolve_name(text: &SmolStr) -> SmolStr {
-    let raw_start = "r#";
-    if text.as_str().starts_with(raw_start) {
-        SmolStr::new(&text[raw_start.len()..])
-    } else {
-        text.clone()
-    }
-}
+pub(crate) const INTO_ITERATOR_TYPE: Name = Name::new_inline_ascii(12, b"IntoIterator");
+pub(crate) const ITEM_TYPE: Name = Name::new_inline_ascii(4, b"Item");
+pub(crate) const TRY_TYPE: Name = Name::new_inline_ascii(3, b"Try");
+pub(crate) const OK_TYPE: Name = Name::new_inline_ascii(2, b"Ok");
+pub(crate) const FUTURE_TYPE: Name = Name::new_inline_ascii(6, b"Future");
+pub(crate) const RESULT_TYPE: Name = Name::new_inline_ascii(6, b"Result");
+pub(crate) const OUTPUT_TYPE: Name = Name::new_inline_ascii(6, b"Output");
+pub(crate) const TARGET_TYPE: Name = Name::new_inline_ascii(6, b"Target");
+pub(crate) const BOX_TYPE: Name = Name::new_inline_ascii(3, b"Box");
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs
index b808a0c36c..67adcfa288 100644
--- a/crates/ra_hir/src/nameres.rs
+++ b/crates/ra_hir/src/nameres.rs
@@ -332,6 +332,20 @@ impl CrateDefMap {
     ) -> ResolvePathResult {
         let mut segments = path.segments.iter().enumerate();
         let mut curr_per_ns: PerNs = match path.kind {
+            PathKind::DollarCrate(krate) => {
+                if krate == self.krate {
+                    tested_by!(macro_dollar_crate_self);
+                    PerNs::types(Module { krate: self.krate, module_id: self.root }.into())
+                } else {
+                    match krate.root_module(db) {
+                        Some(module) => {
+                            tested_by!(macro_dollar_crate_other);
+                            PerNs::types(module.into())
+                        }
+                        None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
+                    }
+                }
+            }
             PathKind::Crate => {
                 PerNs::types(Module { krate: self.krate, module_id: self.root }.into())
             }
diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs
index ef7dc6ebe3..65929c522b 100644
--- a/crates/ra_hir/src/nameres/collector.rs
+++ b/crates/ra_hir/src/nameres/collector.rs
@@ -662,7 +662,10 @@ where
         // Case 1: macro rules, define a macro in crate-global mutable scope
         if is_macro_rules(&mac.path) {
             if let Some(name) = &mac.name {
-                let macro_id = MacroDefId(mac.ast_id.with_file_id(self.file_id));
+                let macro_id = MacroDefId {
+                    ast_id: mac.ast_id.with_file_id(self.file_id),
+                    krate: self.def_collector.def_map.krate,
+                };
                 let macro_ = MacroDef { id: macro_id };
                 self.def_collector.define_macro(self.module_id, name.clone(), macro_, mac.export);
             }
diff --git a/crates/ra_hir/src/nameres/raw.rs b/crates/ra_hir/src/nameres/raw.rs
index 29aaddbf1b..c494b95b0e 100644
--- a/crates/ra_hir/src/nameres/raw.rs
+++ b/crates/ra_hir/src/nameres/raw.rs
@@ -9,7 +9,7 @@ use test_utils::tested_by;
 
 use crate::{
     db::{AstDatabase, DefDatabase},
-    AsName, AstIdMap, Either, FileAstId, HirFileId, ModuleSource, Name, Path,
+    AsName, AstIdMap, Either, FileAstId, HirFileId, ModuleSource, Name, Path, Source,
 };
 
 /// `RawItems` is a set of top-level items in a file (except for impls).
@@ -71,6 +71,8 @@ impl RawItems {
             raw_items: RawItems::default(),
             source_ast_id_map: db.ast_id_map(file_id),
             source_map: ImportSourceMap::default(),
+            file_id,
+            db,
         };
         if let Some(node) = db.parse_or_expand(file_id) {
             if let Some(source_file) = ast::SourceFile::cast(node.clone()) {
@@ -192,13 +194,15 @@ pub(super) struct MacroData {
     pub(super) export: bool,
 }
 
-struct RawItemsCollector {
+struct RawItemsCollector<DB> {
     raw_items: RawItems,
     source_ast_id_map: Arc<AstIdMap>,
     source_map: ImportSourceMap,
+    file_id: HirFileId,
+    db: DB,
 }
 
-impl RawItemsCollector {
+impl<DB: AstDatabase> RawItemsCollector<&DB> {
     fn process_module(&mut self, current_module: Option<Module>, body: impl ast::ModuleItemOwner) {
         for item_or_macro in body.items_with_macros() {
             match item_or_macro {
@@ -300,17 +304,21 @@ impl RawItemsCollector {
     fn add_use_item(&mut self, current_module: Option<Module>, use_item: ast::UseItem) {
         let is_prelude = use_item.has_atom_attr("prelude_import");
 
-        Path::expand_use_item(&use_item, |path, use_tree, is_glob, alias| {
-            let import_data = ImportData {
-                path,
-                alias,
-                is_glob,
-                is_prelude,
-                is_extern_crate: false,
-                is_macro_use: false,
-            };
-            self.push_import(current_module, import_data, Either::A(AstPtr::new(use_tree)));
-        })
+        Path::expand_use_item(
+            Source { ast: use_item, file_id: self.file_id },
+            self.db,
+            |path, use_tree, is_glob, alias| {
+                let import_data = ImportData {
+                    path,
+                    alias,
+                    is_glob,
+                    is_prelude,
+                    is_extern_crate: false,
+                    is_macro_use: false,
+                };
+                self.push_import(current_module, import_data, Either::A(AstPtr::new(use_tree)));
+            },
+        )
     }
 
     fn add_extern_crate_item(
@@ -335,7 +343,10 @@ impl RawItemsCollector {
     }
 
     fn add_macro(&mut self, current_module: Option<Module>, m: ast::MacroCall) {
-        let path = match m.path().and_then(Path::from_ast) {
+        let path = match m
+            .path()
+            .and_then(|path| Path::from_src(Source { ast: path, file_id: self.file_id }, self.db))
+        {
             Some(it) => it,
             _ => return,
         };
diff --git a/crates/ra_hir/src/path.rs b/crates/ra_hir/src/path.rs
index 39d1b7e46f..158c853d42 100644
--- a/crates/ra_hir/src/path.rs
+++ b/crates/ra_hir/src/path.rs
@@ -5,7 +5,7 @@ use ra_syntax::{
     AstNode,
 };
 
-use crate::{name, type_ref::TypeRef, AsName, Name};
+use crate::{db::AstDatabase, name, type_ref::TypeRef, AsName, Crate, Name, Source};
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct Path {
@@ -52,16 +52,19 @@ pub enum PathKind {
     Abs,
     // Type based path like `<T>::foo`
     Type(Box<TypeRef>),
+    // `$crate` from macro expansion
+    DollarCrate(Crate),
 }
 
 impl Path {
     /// Calls `cb` with all paths, represented by this use item.
     pub fn expand_use_item(
-        item: &ast::UseItem,
+        item_src: Source<ast::UseItem>,
+        db: &impl AstDatabase,
         mut cb: impl FnMut(Path, &ast::UseTree, bool, Option<Name>),
     ) {
-        if let Some(tree) = item.use_tree() {
-            expand_use_tree(None, tree, &mut cb);
+        if let Some(tree) = item_src.ast.use_tree() {
+            expand_use_tree(None, tree, &|| item_src.file_id.macro_crate(db), &mut cb);
         }
     }
 
@@ -76,7 +79,19 @@ impl Path {
     }
 
     /// Converts an `ast::Path` to `Path`. Works with use trees.
-    pub fn from_ast(mut path: ast::Path) -> Option<Path> {
+    /// DEPRECATED: It does not handle `$crate` from macro call.
+    pub fn from_ast(path: ast::Path) -> Option<Path> {
+        Path::parse(path, &|| None)
+    }
+
+    /// Converts an `ast::Path` to `Path`. Works with use trees.
+    /// It correctly handles `$crate` based path from macro call.
+    pub fn from_src(source: Source<ast::Path>, db: &impl AstDatabase) -> Option<Path> {
+        let file_id = source.file_id;
+        Path::parse(source.ast, &|| file_id.macro_crate(db))
+    }
+
+    fn parse(mut path: ast::Path, macro_crate: &impl Fn() -> Option<Crate>) -> Option<Path> {
         let mut kind = PathKind::Plain;
         let mut segments = Vec::new();
         loop {
@@ -88,6 +103,13 @@ impl Path {
 
             match segment.kind()? {
                 ast::PathSegmentKind::Name(name) => {
+                    if name.text() == "$crate" {
+                        if let Some(macro_crate) = macro_crate() {
+                            kind = PathKind::DollarCrate(macro_crate);
+                            break;
+                        }
+                    }
+
                     let args = segment
                         .type_arg_list()
                         .and_then(GenericArgs::from_ast)
@@ -113,7 +135,7 @@ impl Path {
                         }
                         // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo
                         Some(trait_ref) => {
-                            let path = Path::from_ast(trait_ref.path()?)?;
+                            let path = Path::parse(trait_ref.path()?, macro_crate)?;
                             kind = path.kind;
                             let mut prefix_segments = path.segments;
                             prefix_segments.reverse();
@@ -264,6 +286,7 @@ impl From<Name> for Path {
 fn expand_use_tree(
     prefix: Option<Path>,
     tree: ast::UseTree,
+    macro_crate: &impl Fn() -> Option<Crate>,
     cb: &mut impl FnMut(Path, &ast::UseTree, bool, Option<Name>),
 ) {
     if let Some(use_tree_list) = tree.use_tree_list() {
@@ -272,13 +295,13 @@ fn expand_use_tree(
             None => prefix,
             // E.g. `use something::{inner}` (prefix is `None`, path is `something`)
             // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`)
-            Some(path) => match convert_path(prefix, path) {
+            Some(path) => match convert_path(prefix, path, macro_crate) {
                 Some(it) => Some(it),
                 None => return, // FIXME: report errors somewhere
             },
         };
         for child_tree in use_tree_list.use_trees() {
-            expand_use_tree(prefix.clone(), child_tree, cb);
+            expand_use_tree(prefix.clone(), child_tree, macro_crate, cb);
         }
     } else {
         let alias = tree.alias().and_then(|a| a.name()).map(|a| a.as_name());
@@ -295,7 +318,7 @@ fn expand_use_tree(
                     }
                 }
             }
-            if let Some(path) = convert_path(prefix, ast_path) {
+            if let Some(path) = convert_path(prefix, ast_path, macro_crate) {
                 let is_glob = tree.has_star();
                 cb(path, &tree, is_glob, alias)
             }
@@ -305,12 +328,29 @@ fn expand_use_tree(
     }
 }
 
-fn convert_path(prefix: Option<Path>, path: ast::Path) -> Option<Path> {
-    let prefix =
-        if let Some(qual) = path.qualifier() { Some(convert_path(prefix, qual)?) } else { prefix };
+fn convert_path(
+    prefix: Option<Path>,
+    path: ast::Path,
+    macro_crate: &impl Fn() -> Option<Crate>,
+) -> Option<Path> {
+    let prefix = if let Some(qual) = path.qualifier() {
+        Some(convert_path(prefix, qual, macro_crate)?)
+    } else {
+        prefix
+    };
+
     let segment = path.segment()?;
     let res = match segment.kind()? {
         ast::PathSegmentKind::Name(name) => {
+            if name.text() == "$crate" {
+                if let Some(krate) = macro_crate() {
+                    return Some(Path::from_simple_segments(
+                        PathKind::DollarCrate(krate),
+                        iter::empty(),
+                    ));
+                }
+            }
+
             // no type args in use
             let mut res = prefix
                 .unwrap_or_else(|| Path { kind: PathKind::Plain, segments: Vec::with_capacity(1) });
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index bd4be84301..6e89bfc765 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -203,6 +203,7 @@ impl SourceAnalyzer {
         db: &impl HirDatabase,
         macro_call: &ast::MacroCall,
     ) -> Option<MacroDef> {
+        // This must be a normal source file rather than macro file.
         let path = macro_call.path().and_then(Path::from_ast)?;
         self.resolver.resolve_path_as_macro(db, &path)
     }
@@ -261,6 +262,7 @@ impl SourceAnalyzer {
                 return Some(PathResolution::AssocItem(assoc));
             }
         }
+        // This must be a normal source file rather than macro file.
         let hir_path = crate::Path::from_ast(path.clone())?;
         self.resolve_hir_path(db, &hir_path)
     }
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index db33773572..8f92468e67 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -609,7 +609,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
 
         for (i, &subpat) in subpats.iter().enumerate() {
             let expected_ty = def
-                .and_then(|d| d.field(self.db, &Name::tuple_field_name(i)))
+                .and_then(|d| d.field(self.db, &Name::new_tuple_field(i)))
                 .map_or(Ty::Unknown, |field| field.ty(self.db))
                 .subst(&substs);
             let expected_ty = self.normalize_associated_types_in(expected_ty);
@@ -1375,10 +1375,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
                 )
                 .find_map(|derefed_ty| match canonicalized.decanonicalize_ty(derefed_ty.value) {
                     Ty::Apply(a_ty) => match a_ty.ctor {
-                        TypeCtor::Tuple { .. } => {
-                            let i = name.to_string().parse::<usize>().ok();
-                            i.and_then(|i| a_ty.parameters.0.get(i).cloned())
-                        }
+                        TypeCtor::Tuple { .. } => name
+                            .as_tuple_index()
+                            .and_then(|idx| a_ty.parameters.0.get(idx).cloned()),
                         TypeCtor::Adt(Adt::Struct(s)) => s.field(self.db, name).map(|field| {
                             self.write_field_resolution(tgt_expr, field);
                             field.ty(self.db).subst(&a_ty.parameters)
diff --git a/crates/ra_hir/src/type_ref.rs b/crates/ra_hir/src/type_ref.rs
index bc8acc7eed..2cf06b2504 100644
--- a/crates/ra_hir/src/type_ref.rs
+++ b/crates/ra_hir/src/type_ref.rs
@@ -72,6 +72,7 @@ impl TypeRef {
             }
             ast::TypeRef::NeverType(..) => TypeRef::Never,
             ast::TypeRef::PathType(inner) => {
+                // FIXME: Use `Path::from_src`
                 inner.path().and_then(Path::from_ast).map(TypeRef::Path).unwrap_or(TypeRef::Error)
             }
             ast::TypeRef::PointerType(inner) => {
@@ -141,6 +142,7 @@ impl TypeBound {
                     Some(p) => p,
                     None => return TypeBound::Error,
                 };
+                // FIXME: Use `Path::from_src`
                 let path = match Path::from_ast(path) {
                     Some(p) => p,
                     None => return TypeBound::Error,
diff --git a/crates/ra_mbe/src/mbe_expander/transcriber.rs b/crates/ra_mbe/src/mbe_expander/transcriber.rs
index c22680b93a..ed094d5bb4 100644
--- a/crates/ra_mbe/src/mbe_expander/transcriber.rs
+++ b/crates/ra_mbe/src/mbe_expander/transcriber.rs
@@ -86,7 +86,7 @@ fn expand_subtree(ctx: &mut ExpandCtx, template: &tt::Subtree) -> Result<tt::Sub
 
 fn expand_var(ctx: &mut ExpandCtx, v: &SmolStr) -> Result<Fragment, ExpandError> {
     let res = if v == "crate" {
-        // FIXME: Properly handle $crate token
+        // We simply produce identifier `$crate` here. And it will be resolved when lowering ast to Path.
         let tt =
             tt::Leaf::from(tt::Ident { text: "$crate".into(), id: tt::TokenId::unspecified() })
                 .into();
diff --git a/crates/ra_syntax/src/ast/extensions.rs b/crates/ra_syntax/src/ast/extensions.rs
index 5f7e9f5b10..0433edb84e 100644
--- a/crates/ra_syntax/src/ast/extensions.rs
+++ b/crates/ra_syntax/src/ast/extensions.rs
@@ -21,6 +21,16 @@ impl ast::NameRef {
     pub fn text(&self) -> &SmolStr {
         text_of_first_token(self.syntax())
     }
+
+    pub fn as_tuple_field(&self) -> Option<usize> {
+        self.syntax().children_with_tokens().find_map(|c| {
+            if c.kind() == SyntaxKind::INT_NUMBER {
+                c.as_token().and_then(|tok| tok.text().as_str().parse().ok())
+            } else {
+                None
+            }
+        })
+    }
 }
 
 fn text_of_first_token(node: &SyntaxNode) -> &SmolStr {


Test patch:
diff --git a/crates/ra_hir/src/nameres/tests/macros.rs b/crates/ra_hir/src/nameres/tests/macros.rs
index bd60f4258d..e4b4083948 100644
--- a/crates/ra_hir/src/nameres/tests/macros.rs
+++ b/crates/ra_hir/src/nameres/tests/macros.rs
@@ -515,3 +515,108 @@ fn path_qualified_macros() {
         ⋮not_found: _
     "###);
 }
+
+#[test]
+fn macro_dollar_crate_is_correct_in_item() {
+    covers!(macro_dollar_crate_self);
+    covers!(macro_dollar_crate_other);
+    let map = def_map_with_crate_graph(
+        "
+        //- /main.rs
+        #[macro_use]
+        extern crate foo;
+
+        #[macro_use]
+        mod m {
+            macro_rules! current {
+                () => {
+                    use $crate::Foo as FooSelf;
+                }
+            }
+        }
+
+        struct Foo;
+
+        current!();
+        not_current1!();
+        foo::not_current2!();
+
+        //- /lib.rs
+        mod m {
+            #[macro_export]
+            macro_rules! not_current1 {
+                () => {
+                    use $crate::Bar;
+                }
+            }
+        }
+
+        #[macro_export]
+        macro_rules! not_current2 {
+            () => {
+                use $crate::Baz;
+            }
+        }
+
+        struct Bar;
+        struct Baz;
+        ",
+        crate_graph! {
+            "main": ("/main.rs", ["foo"]),
+            "foo": ("/lib.rs", []),
+        },
+    );
+    assert_snapshot!(map, @r###"
+        ⋮crate
+        ⋮Bar: t v
+        ⋮Baz: t v
+        ⋮Foo: t v
+        ⋮FooSelf: t v
+        ⋮foo: t
+        ⋮m: t
+        ⋮
+        ⋮crate::m
+    "###);
+}
+
+#[test]
+fn macro_dollar_crate_is_correct_in_indirect_deps() {
+    covers!(macro_dollar_crate_other);
+    // From std
+    let map = def_map_with_crate_graph(
+        r#"
+        //- /main.rs
+        foo!();
+
+        //- /std.rs
+        #[prelude_import]
+        use self::prelude::*;
+
+        pub use core::foo;
+
+        mod prelude {}
+
+        #[macro_use]
+        mod std_macros;
+
+        //- /core.rs
+        #[macro_export]
+        macro_rules! foo {
+            () => {
+                use $crate::bar;
+            }
+        }
+
+        pub struct bar;
+        "#,
+        crate_graph! {
+            "main": ("/main.rs", ["std"]),
+            "std": ("/std.rs", ["core"]),
+            "core": ("/core.rs", []),
+        },
+    );
+    assert_snapshot!(map, @r###"
+        ⋮crate
+        ⋮bar: t v
+    "###);
+}
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index 4362bb27a3..bd2b07755c 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -3130,6 +3130,39 @@ fn test() { S.foo()<|>; }
     assert_eq!(t, "u128");
 }
 
+#[test]
+fn infer_macro_with_dollar_crate_is_correct_in_expr() {
+    covers!(macro_dollar_crate_other);
+    let (mut db, pos) = MockDatabase::with_position(
+        r#"
+//- /main.rs
+fn test() {
+    let x = (foo::foo!(1), foo::foo!(2));
+    x<|>;
+}
+
+//- /lib.rs
+#[macro_export]
+macro_rules! foo {
+    (1) => { $crate::bar!() };
+    (2) => { 1 + $crate::baz() };
+}
+
+#[macro_export]
+macro_rules! bar {
+    () => { 42 }
+}
+
+pub fn baz() -> usize { 31usize }
+"#,
+    );
+    db.set_crate_graph_from_fixture(crate_graph! {
+        "main": ("/main.rs", ["foo"]),
+        "foo": ("/lib.rs", []),
+    });
+    assert_eq!("(i32, usize)", type_at_pos(&db, pos));
+}
+
 #[ignore]
 #[test]
 fn method_resolution_trait_before_autoref() {