Repository: rust-analyzer/rust-analyzer
Pull request #8097 (2021-03-18 21:29:38)

Parse extended_key_value_attributes
Companion PR https://github.com/rust-analyzer/ungrammar/pull/31


Patch:
diff --git a/Cargo.lock b/Cargo.lock
index b99c243a47..9f013c2757 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1809,9 +1809,9 @@ checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
 
 [[package]]
 name = "ungrammar"
-version = "1.12.2"
+version = "1.13.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "df6586a7c530704efe803d49a0b4132dcbdb4063163df39110548e6b5f2373ba"
+checksum = "76760314176cc2b94047af2f921b92c39f11a34dc05c43a3c2b0fc91cb22959f"
 
 [[package]]
 name = "unicase"
diff --git a/crates/hir/src/has_source.rs b/crates/hir/src/has_source.rs
index d57fad9ed3..2620026713 100644
--- a/crates/hir/src/has_source.rs
+++ b/crates/hir/src/has_source.rs
@@ -6,7 +6,7 @@ use hir_def::{
     src::{HasChildSource, HasSource as _},
     Lookup, VariantId,
 };
-use hir_expand::{InFile, MacroDefKind};
+use hir_expand::InFile;
 use syntax::ast;
 
 use crate::{
@@ -111,17 +111,10 @@ impl HasSource for TypeAlias {
     }
 }
 impl HasSource for MacroDef {
-    type Ast = Either<ast::Macro, ast::Fn>;
+    type Ast = ast::Macro;
     fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
-        Some(match &self.id.kind {
-            MacroDefKind::Declarative(id)
-            | MacroDefKind::BuiltIn(_, id)
-            | MacroDefKind::BuiltInDerive(_, id)
-            | MacroDefKind::BuiltInEager(_, id) => {
-                id.with_value(Either::Left(id.to_node(db.upcast())))
-            }
-            MacroDefKind::ProcMacro(_, id) => id.map(|_| Either::Right(id.to_node(db.upcast()))),
-        })
+        let ast_id = self.id.ast_id?;
+        Some(InFile { file_id: ast_id.file_id, value: ast_id.to_node(db.upcast()) })
     }
 }
 impl HasSource for Impl {
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 67ec8e82a2..b41a36a781 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -1144,21 +1144,17 @@ impl MacroDef {
 
     /// XXX: this parses the file
     pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
-        match self.source(db)?.value {
-            Either::Left(it) => it.name().map(|it| it.as_name()),
-            Either::Right(it) => it.name().map(|it| it.as_name()),
-        }
+        self.source(db)?.value.name().map(|it| it.as_name())
     }
 
     /// Indicate it is a proc-macro
     pub fn is_proc_macro(&self) -> bool {
-        matches!(self.id.kind, MacroDefKind::ProcMacro(..))
+        matches!(self.id.kind, MacroDefKind::ProcMacro(_))
     }
 
     /// Indicate it is a derive macro
     pub fn is_derive_macro(&self) -> bool {
-        // FIXME: wrong for `ProcMacro`
-        matches!(self.id.kind, MacroDefKind::ProcMacro(..) | MacroDefKind::BuiltInDerive(..))
+        matches!(self.id.kind, MacroDefKind::ProcMacro(_) | MacroDefKind::BuiltInDerive(_))
     }
 }
 
@@ -1462,7 +1458,7 @@ impl TypeParam {
             .into_iter()
             .filter_map(|pred| match &pred.value {
                 hir_ty::GenericPredicate::Implemented(trait_ref) => {
-                    Some(Trait::from(trait_ref.hir_trait_id()))
+                    Some(Trait::from(trait_ref.trait_))
                 }
                 _ => None,
             })
@@ -1757,8 +1753,8 @@ impl Type {
 
     pub fn impls_trait(&self, db: &dyn HirDatabase, trait_: Trait, args: &[Type]) -> bool {
         let trait_ref = hir_ty::TraitRef {
-            trait_id: hir_ty::to_chalk_trait_id(trait_.id),
-            substitution: Substitution::build_for_def(db, trait_.id)
+            trait_: trait_.id,
+            substs: Substitution::build_for_def(db, trait_.id)
                 .push(self.ty.value.clone())
                 .fill(args.iter().map(|t| t.ty.value.clone()))
                 .build(),
@@ -2023,7 +2019,7 @@ impl Type {
             it.into_iter()
                 .filter_map(|pred| match pred {
                     hir_ty::GenericPredicate::Implemented(trait_ref) => {
-                        Some(Trait::from(trait_ref.hir_trait_id()))
+                        Some(Trait::from(trait_ref.trait_))
                     }
                     _ => None,
                 })
@@ -2067,7 +2063,7 @@ impl Type {
                 match pred {
                     GenericPredicate::Implemented(trait_ref) => {
                         cb(type_.clone());
-                        walk_substs(db, type_, &trait_ref.substitution, cb);
+                        walk_substs(db, type_, &trait_ref.substs, cb);
                     }
                     _ => (),
                 }
diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs
index 762809fcd0..c6ad5ecb5f 100644
--- a/crates/hir/src/semantics/source_to_def.rs
+++ b/crates/hir/src/semantics/source_to_def.rs
@@ -195,12 +195,12 @@ impl SourceToDefCtx<'_, '_> {
         &mut self,
         src: InFile<ast::MacroRules>,
     ) -> Option<MacroDefId> {
-        let file_ast_id = self.db.ast_id_map(src.file_id).ast_id(&src.value);
-        let ast_id = AstId::new(src.file_id, file_ast_id.upcast());
-        let kind = MacroDefKind::Declarative(ast_id);
+        let kind = MacroDefKind::Declarative;
         let file_id = src.file_id.original_file(self.db.upcast());
         let krate = self.file_to_def(file_id).get(0).copied()?.krate();
-        Some(MacroDefId { krate, kind, local_inner: false })
+        let file_ast_id = self.db.ast_id_map(src.file_id).ast_id(&src.value);
+        let ast_id = Some(AstId::new(src.file_id, file_ast_id.upcast()));
+        Some(MacroDefId { krate, ast_id, kind, local_inner: false })
     }
 
     pub(super) fn find_container(&mut self, src: InFile<&SyntaxNode>) -> Option<ChildContainer> {
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs
index 1cab0e363f..85d01ac3e9 100644
--- a/crates/hir_def/src/attr.rs
+++ b/crates/hir_def/src/attr.rs
@@ -209,7 +209,7 @@ impl Attrs {
             },
             AttrDefId::TraitId(it) => attrs_from_item_tree(it.lookup(db).id, db),
             AttrDefId::MacroDefId(it) => {
-                it.ast_id().map_or_else(Default::default, |ast_id| attrs_from_ast(ast_id, db))
+                it.ast_id.map_or_else(Default::default, |ast_id| attrs_from_ast(ast_id, db))
             }
             AttrDefId::ImplId(it) => attrs_from_item_tree(it.lookup(db).id, db),
             AttrDefId::ConstId(it) => attrs_from_item_tree(it.lookup(db).id, db),
@@ -283,51 +283,8 @@ impl Attrs {
     /// Constructs a map that maps the lowered `Attr`s in this `Attrs` back to its original syntax nodes.
     ///
     /// `owner` must be the original owner of the attributes.
-    // FIXME: figure out a better api that doesnt require the for_module hack
-    pub fn source_map(&self, owner: InFile<&dyn ast::AttrsOwner>) -> AttrSourceMap {
-        // FIXME: This doesn't work correctly for modules, as the attributes there can have up to
-        // two different owners
-        AttrSourceMap {
-            attrs: collect_attrs(owner.value)
-                .map(|attr| InFile::new(owner.file_id, attr))
-                .collect(),
-        }
-    }
-
-    pub fn source_map_for_module(
-        &self,
-        db: &dyn DefDatabase,
-        module: crate::ModuleId,
-    ) -> AttrSourceMap {
-        let def_map = module.def_map(db);
-        let mod_data = &def_map[module.local_id];
-        let attrs = match mod_data.declaration_source(db) {
-            Some(it) => {
-                let mut attrs: Vec<_> = collect_attrs(&it.value as &dyn ast::AttrsOwner)
-                    .map(|attr| InFile::new(it.file_id, attr))
-                    .collect();
-                if let InFile { file_id, value: ModuleSource::SourceFile(file) } =
-                    mod_data.definition_source(db)
-                {
-                    attrs.extend(
-                        collect_attrs(&file as &dyn ast::AttrsOwner)
-                            .map(|attr| InFile::new(file_id, attr)),
-                    )
-                }
-                attrs
-            }
-            None => {
-                let InFile { file_id, value } = mod_data.definition_source(db);
-                match &value {
-                    ModuleSource::SourceFile(file) => collect_attrs(file as &dyn ast::AttrsOwner),
-                    ModuleSource::Module(module) => collect_attrs(module as &dyn ast::AttrsOwner),
-                    ModuleSource::BlockExpr(block) => collect_attrs(block as &dyn ast::AttrsOwner),
-                }
-                .map(|attr| InFile::new(file_id, attr))
-                .collect()
-            }
-        };
-        AttrSourceMap { attrs }
+    pub fn source_map(&self, owner: &dyn ast::AttrsOwner) -> AttrSourceMap {
+        AttrSourceMap { attrs: collect_attrs(owner).collect() }
     }
 
     pub fn by_key(&self, key: &'static str) -> AttrQuery<'_> {
@@ -422,7 +379,7 @@ fn inner_attributes(
 }
 
 pub struct AttrSourceMap {
-    attrs: Vec<InFile<Either<ast::Attr, ast::Comment>>>,
+    attrs: Vec<Either<ast::Attr, ast::Comment>>,
 }
 
 impl AttrSourceMap {
@@ -432,11 +389,10 @@ impl AttrSourceMap {
     ///
     /// Note that the returned syntax node might be a `#[cfg_attr]`, or a doc comment, instead of
     /// the attribute represented by `Attr`.
-    pub fn source_of(&self, attr: &Attr) -> InFile<&Either<ast::Attr, ast::Comment>> {
+    pub fn source_of(&self, attr: &Attr) -> &Either<ast::Attr, ast::Comment> {
         self.attrs
             .get(attr.index as usize)
             .unwrap_or_else(|| panic!("cannot find `Attr` at index {}", attr.index))
-            .as_ref()
     }
 }
 
@@ -458,7 +414,7 @@ pub enum AttrInput {
 impl Attr {
     fn from_src(ast: ast::Attr, hygiene: &Hygiene, index: u32) -> Option<Attr> {
         let path = ModPath::from_src(ast.path()?, hygiene)?;
-        let input = if let Some(lit) = ast.literal() {
+        let input = if let Some(ast::Expr::Literal(lit)) = ast.expr() {
             let value = match lit.kind() {
                 ast::LiteralKind::String(string) => string.value()?.into(),
                 _ => lit.syntax().first_token()?.text().trim_matches('"').into(),
@@ -472,6 +428,18 @@ impl Attr {
         Some(Attr { index, path, input })
     }
 
+    /// Maps this lowered `Attr` back to its original syntax node.
+    ///
+    /// `owner` must be the original owner of the attribute.
+    ///
+    /// Note that the returned syntax node might be a `#[cfg_attr]`, or a doc comment, instead of
+    /// the attribute represented by `Attr`.
+    pub fn to_src(&self, owner: &dyn ast::AttrsOwner) -> Either<ast::Attr, ast::Comment> {
+        collect_attrs(owner).nth(self.index as usize).unwrap_or_else(|| {
+            panic!("cannot find `Attr` at index {} in {}", self.index, owner.syntax())
+        })
+    }
+
     /// Parses this attribute as a `#[derive]`, returns an iterator that yields all contained paths
     /// to derive macros.
     ///
diff --git a/crates/hir_def/src/import_map.rs b/crates/hir_def/src/import_map.rs
index 960cabb5fd..369bc3350b 100644
--- a/crates/hir_def/src/import_map.rs
+++ b/crates/hir_def/src/import_map.rs
@@ -912,10 +912,10 @@ mod tests {
                 dep::fmt (t)
                 dep::format (f)
                 dep::Fmt (v)
-                dep::Fmt (m)
+                dep::fmt::Display (t)
                 dep::Fmt (t)
                 dep::fmt::Display::fmt (a)
-                dep::fmt::Display (t)
+                dep::Fmt (m)
             "#]],
         );
 
@@ -926,9 +926,9 @@ mod tests {
             expect![[r#"
                 dep::fmt (t)
                 dep::Fmt (v)
-                dep::Fmt (m)
                 dep::Fmt (t)
                 dep::fmt::Display::fmt (a)
+                dep::Fmt (m)
             "#]],
         );
 
@@ -939,10 +939,10 @@ mod tests {
             expect![[r#"
                 dep::fmt (t)
                 dep::Fmt (v)
-                dep::Fmt (m)
+                dep::fmt::Display (t)
                 dep::Fmt (t)
                 dep::fmt::Display::fmt (a)
-                dep::fmt::Display (t)
+                dep::Fmt (m)
             "#]],
         );
     }
@@ -980,10 +980,10 @@ mod tests {
             expect![[r#"
                 dep::fmt (t)
                 dep::Fmt (v)
-                dep::Fmt (m)
+                dep::fmt::Display (t)
                 dep::Fmt (t)
                 dep::fmt::Display::fmt (a)
-                dep::fmt::Display (t)
+                dep::Fmt (m)
             "#]],
         );
 
@@ -994,9 +994,9 @@ mod tests {
             expect![[r#"
                 dep::fmt (t)
                 dep::Fmt (v)
-                dep::Fmt (m)
                 dep::Fmt (t)
                 dep::fmt::Display::fmt (a)
+                dep::Fmt (m)
             "#]],
         );
     }
@@ -1058,8 +1058,8 @@ mod tests {
             Query::new("".to_string()).limit(2),
             expect![[r#"
                 dep::fmt (t)
-                dep::Fmt (m)
                 dep::Fmt (t)
+                dep::Fmt (m)
                 dep::Fmt (v)
             "#]],
         );
diff --git a/crates/hir_def/src/item_scope.rs b/crates/hir_def/src/item_scope.rs
index f3ebe7c727..aafd73b606 100644
--- a/crates/hir_def/src/item_scope.rs
+++ b/crates/hir_def/src/item_scope.rs
@@ -252,7 +252,7 @@ impl ItemScope {
             .for_each(|vis| *vis = Visibility::Module(this_module));
 
         for (mac, vis) in self.macros.values_mut() {
-            if let MacroDefKind::ProcMacro(..) = mac.kind {
+            if let MacroDefKind::ProcMacro(_) = mac.kind {
                 // FIXME: Technically this is insufficient since reexports of proc macros are also
                 // forbidden. Practically nobody does that.
                 continue;
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs
index 50e7304447..6758411a0c 100644
--- a/crates/hir_def/src/lib.rs
+++ b/crates/hir_def/src/lib.rs
@@ -76,11 +76,7 @@ use stdx::impl_from;
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct ModuleId {
     krate: CrateId,
-    /// If this `ModuleId` was derived from a `DefMap` for a block expression, this stores the
-    /// `BlockId` of that block expression. If `None`, this module is part of the crate-level
-    /// `DefMap` of `krate`.
     block: Option<BlockId>,
-    /// The module's ID in its originating `DefMap`.
     pub local_id: LocalModuleId,
 }
 
@@ -91,7 +87,7 @@ impl ModuleId {
                 db.block_def_map(block).unwrap_or_else(|| {
                     // NOTE: This should be unreachable - all `ModuleId`s come from their `DefMap`s,
                     // so the `DefMap` here must exist.
-                    unreachable!("no `block_def_map` for `ModuleId` {:?}", self);
+                    panic!("no `block_def_map` for `ModuleId` {:?}", self);
                 })
             }
             None => db.crate_def_map(self.krate),
@@ -654,7 +650,7 @@ fn macro_call_as_call_id(
 ) -> Result<Result<MacroCallId, ErrorEmitted>, UnresolvedMacro> {
     let def: MacroDefId = resolver(call.path.clone()).ok_or(UnresolvedMacro)?;
 
-    let res = if let MacroDefKind::BuiltInEager(..) = def.kind {
+    let res = if let MacroDefKind::BuiltInEager(_) = def.kind {
         let macro_call = InFile::new(call.ast_id.file_id, call.ast_id.to_node(db.upcast()));
         let hygiene = Hygiene::new(db.upcast(), call.ast_id.file_id);
 
diff --git a/crates/hir_def/src/nameres.rs b/crates/hir_def/src/nameres.rs
index 1ac326f971..c97be584e2 100644
--- a/crates/hir_def/src/nameres.rs
+++ b/crates/hir_def/src/nameres.rs
@@ -53,12 +53,11 @@ mod path_resolution;
 
 #[cfg(test)]
 mod tests;
-mod proc_macro;
 
 use std::sync::Arc;
 
 use base_db::{CrateId, Edition, FileId};
-use hir_expand::{diagnostics::DiagnosticSink, name::Name, InFile, MacroDefId};
+use hir_expand::{diagnostics::DiagnosticSink, name::Name, InFile};
 use la_arena::Arena;
 use profile::Count;
 use rustc_hash::FxHashMap;
@@ -74,8 +73,6 @@ use crate::{
     AstId, BlockId, BlockLoc, LocalModuleId, ModuleDefId, ModuleId,
 };
 
-use self::proc_macro::ProcMacroDef;
-
 /// Contains the results of (early) name resolution.
 ///
 /// A `DefMap` stores the module tree and the definitions that are in scope in every module after
@@ -98,12 +95,6 @@ pub struct DefMap {
     prelude: Option<ModuleId>,
     extern_prelude: FxHashMap<Name, ModuleDefId>,
 
-    /// Side table with additional proc. macro info, for use by name resolution in downstream
-    /// crates.
-    ///
-    /// (the primary purpose is to resolve derive helpers)
-    exported_proc_macros: FxHashMap<MacroDefId, ProcMacroDef>,
-
     edition: Edition,
     diagnostics: Vec<DefDiagnostic>,
 }
@@ -246,7 +237,6 @@ impl DefMap {
             krate,
             edition,
             extern_prelude: FxHashMap::default(),
-            exported_proc_macros: FxHashMap::default(),
             prelude: None,
             root,
             modules,
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index dcedf7766d..d0fefb5afd 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -18,6 +18,7 @@ use hir_expand::{
 use hir_expand::{InFile, MacroCallLoc};
 use rustc_hash::{FxHashMap, FxHashSet};
 use syntax::ast;
+use tt::{Leaf, TokenTree};
 
 use crate::{
     attr::Attrs,
@@ -41,8 +42,6 @@ use crate::{
     UnresolvedMacro,
 };
 
-use super::proc_macro::ProcMacroDef;
-
 const GLOB_RECURSION_LIMIT: usize = 100;
 const EXPANSION_DEPTH_LIMIT: usize = 128;
 const FIXED_POINT_LIMIT: usize = 8192;
@@ -354,23 +353,24 @@ impl DefCollector<'_> {
     /// use a dummy expander that always errors. This comes with the drawback of macros potentially
     /// going out of sync with what the build system sees (since we resolve using VFS state, but
     /// Cargo builds only on-disk files). We could and probably should add diagnostics for that.
-    fn export_proc_macro(&mut self, def: ProcMacroDef, ast_id: AstId<ast::Fn>) {
+    fn resolve_proc_macro(&mut self, name: &Name) {
         self.exports_proc_macros = true;
-        let macro_def = match self.proc_macros.iter().find(|(n, _)| n == &def.name) {
+        let macro_def = match self.proc_macros.iter().find(|(n, _)| n == name) {
             Some((_, expander)) => MacroDefId {
+                ast_id: None,
                 krate: self.def_map.krate,
-                kind: MacroDefKind::ProcMacro(*expander, ast_id),
+                kind: MacroDefKind::ProcMacro(*expander),
                 local_inner: false,
             },
             None => MacroDefId {
+                ast_id: None,
                 krate: self.def_map.krate,
-                kind: MacroDefKind::ProcMacro(ProcMacroExpander::dummy(self.def_map.krate), ast_id),
+                kind: MacroDefKind::ProcMacro(ProcMacroExpander::dummy(self.def_map.krate)),
                 local_inner: false,
             },
         };
 
-        self.define_proc_macro(def.name.clone(), macro_def);
-        self.def_map.exported_proc_macros.insert(macro_def, def);
+        self.define_proc_macro(name.clone(), macro_def);
     }
 
     /// Define a macro with `macro_rules`.
@@ -1118,8 +1118,7 @@ impl ModCollector<'_, '_> {
                 ModItem::Function(id) => {
                     let func = &self.item_tree[id];
 
-                    let ast_id = InFile::new(self.file_id, func.ast_id);
-                    self.collect_proc_macro_def(&func.name, ast_id, &attrs);
+                    self.collect_proc_macro_def(&func.name, &attrs);
 
                     def = Some(DefData {
                         id: FunctionLoc {
@@ -1386,11 +1385,28 @@ impl ModCollector<'_, '_> {
     }
 
     /// If `attrs` registers a procedural macro, collects its definition.
-    fn collect_proc_macro_def(&mut self, func_name: &Name, ast_id: AstId<ast::Fn>, attrs: &Attrs) {
+    fn collect_proc_macro_def(&mut self, func_name: &Name, attrs: &Attrs) {
         // FIXME: this should only be done in the root module of `proc-macro` crates, not everywhere
-        if let Some(proc_macro) = attrs.parse_proc_macro_decl(func_name) {
-            self.def_collector.export_proc_macro(proc_macro, ast_id);
-        }
+        // FIXME: distinguish the type of macro
+        let macro_name = if attrs.by_key("proc_macro").exists()
+            || attrs.by_key("proc_macro_attribute").exists()
+        {
+            func_name.clone()
+        } else {
+            let derive = attrs.by_key("proc_macro_derive");
+            if let Some(arg) = derive.tt_values().next() {
+                if let [TokenTree::Leaf(Leaf::Ident(trait_name)), ..] = &*arg.token_trees {
+                    trait_name.as_name()
+                } else {
+                    log::trace!("malformed `#[proc_macro_derive]`: {}", arg);
+                    return;
+                }
+            } else {
+                return;
+            }
+        };
+
+        self.def_collector.resolve_proc_macro(&macro_name);
     }
 
     fn collect_macro_rules(&mut self, id: FileItemTreeId<MacroRules>) {
@@ -1429,8 +1445,9 @@ impl ModCollector<'_, '_> {
 
         // Case 2: normal `macro_rules!` macro
         let macro_id = MacroDefId {
+            ast_id: Some(ast_id),
             krate: self.def_collector.def_map.krate,
-            kind: MacroDefKind::Declarative(ast_id),
+            kind: MacroDefKind::Declarative,
             local_inner: is_local_inner,
         };
         self.def_collector.define_macro(self.module_id, mac.name.clone(), macro_id, is_export);
diff --git a/crates/hir_def/src/nameres/proc_macro.rs b/crates/hir_def/src/nameres/proc_macro.rs
deleted file mode 100644
index 156598f195..0000000000
--- a/crates/hir_def/src/nameres/proc_macro.rs
+++ /dev/null
@@ -1,71 +0,0 @@
-//! Nameres-specific procedural macro data and helpers.
-
-use hir_expand::name::{AsName, Name};
-use tt::{Leaf, TokenTree};
-
-use crate::attr::Attrs;
-
-#[derive(Debug, PartialEq, Eq)]
-pub(super) struct ProcMacroDef {
-    pub(super) name: Name,
-    pub(super) kind: ProcMacroKind,
-}
-
-#[derive(Debug, PartialEq, Eq)]
-pub(super) enum ProcMacroKind {
-    CustomDerive { helpers: Box<[Name]> },
-    FnLike,
-    Attr,
-}
-
-impl Attrs {
-    #[rustfmt::skip]
-    pub(super) fn parse_proc_macro_decl(&self, func_name: &Name) -> Option<ProcMacroDef> {
-        if self.by_key("proc_macro").exists() {
-            Some(ProcMacroDef { name: func_name.clone(), kind: ProcMacroKind::FnLike })
-        } else if self.by_key("proc_macro_attribute").exists() {
-            Some(ProcMacroDef { name: func_name.clone(), kind: ProcMacroKind::Attr })
-        } else if self.by_key("proc_macro_derive").exists() {
-            let derive = self.by_key("proc_macro_derive").tt_values().next().unwrap();
-
-            match &*derive.token_trees {
-                // `#[proc_macro_derive(Trait)]`
-                [TokenTree::Leaf(Leaf::Ident(trait_name))] => Some(ProcMacroDef {
-                    name: trait_name.as_name(),
-                    kind: ProcMacroKind::CustomDerive { helpers: Box::new([]) },
-                }),
-
-                // `#[proc_macro_derive(Trait, attibutes(helper1, helper2, ...))]`
-                [
-                    TokenTree::Leaf(Leaf::Ident(trait_name)),
-                    TokenTree::Leaf(Leaf::Punct(comma)),
-                    TokenTree::Leaf(Leaf::Ident(attributes)),
-                    TokenTree::Subtree(helpers)
-                ] if comma.char == ',' && attributes.text == "attributes" =>
-                {
-                    let helpers = helpers.token_trees.iter()
-                        .filter(|tt| !matches!(tt, TokenTree::Leaf(Leaf::Punct(comma)) if comma.char == ','))
-                        .map(|tt| {
-                            match tt {
-                                TokenTree::Leaf(Leaf::Ident(helper)) => Some(helper.as_name()),
-                                _ => None
-                            }
-                        })
-                        .collect::<Option<Box<[_]>>>()?;
-
-                    Some(ProcMacroDef {
-                        name: trait_name.as_name(),
-                        kind: ProcMacroKind::CustomDerive { helpers },
-                    })
-                }
-
-                _ => {
-                    log::trace!("malformed `#[proc_macro_derive]`: {}", derive);
-                    None
-                }
-            }
-        } else {
-            None
-        }
-    }
-}
diff --git a/crates/hir_expand/src/builtin_derive.rs b/crates/hir_expand/src/builtin_derive.rs
index 60fd2ebdd4..a8d267c30e 100644
--- a/crates/hir_expand/src/builtin_derive.rs
+++ b/crates/hir_expand/src/builtin_derive.rs
@@ -61,7 +61,8 @@ pub fn find_builtin_derive(
     let expander = BuiltinDeriveExpander::find_by_name(ident)?;
     Some(MacroDefId {
         krate,
-        kind: MacroDefKind::BuiltInDerive(expander, ast_id),
+        ast_id: Some(ast_id),
+        kind: MacroDefKind::BuiltInDerive(expander),
         local_inner: false,
     })
 }
@@ -313,7 +314,8 @@ $0
         let loc = MacroCallLoc {
             def: MacroDefId {
                 krate: CrateId(0),
-                kind: MacroDefKind::BuiltInDerive(expander, macro_ast_id),
+                ast_id: Some(macro_ast_id),
+                kind: MacroDefKind::BuiltInDerive(expander),
                 local_inner: false,
             },
             krate: CrateId(0),
diff --git a/crates/hir_expand/src/builtin_macro.rs b/crates/hir_expand/src/builtin_macro.rs
index 8529b43b6d..fce09a9e71 100644
--- a/crates/hir_expand/src/builtin_macro.rs
+++ b/crates/hir_expand/src/builtin_macro.rs
@@ -71,12 +71,14 @@ pub fn find_builtin_macro(
     match kind {
         Either::Left(kind) => Some(MacroDefId {
             krate,
-            kind: MacroDefKind::BuiltIn(kind, ast_id),
+            ast_id: Some(ast_id),
+            kind: MacroDefKind::BuiltIn(kind),
             local_inner: false,
         }),
         Either::Right(kind) => Some(MacroDefId {
             krate,
-            kind: MacroDefKind::BuiltInEager(kind, ast_id),
+            ast_id: Some(ast_id),
+            kind: MacroDefKind::BuiltInEager(kind),
             local_inner: false,
         }),
     }
@@ -510,7 +512,6 @@ mod tests {
         let macro_call = macro_calls.pop().unwrap();
 
         let expander = find_by_name(&macro_rules.name().unwrap().as_name()).unwrap();
-        let ast_id = AstId::new(file_id.into(), ast_id_map.ast_id(&macro_rules));
 
         let krate = CrateId(0);
         let file_id = match expander {
@@ -518,7 +519,8 @@ mod tests {
                 // the first one should be a macro_rules
                 let def = MacroDefId {
                     krate: CrateId(0),
-                    kind: MacroDefKind::BuiltIn(expander, ast_id),
+                    ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(&macro_rules))),
+                    kind: MacroDefKind::BuiltIn(expander),
                     local_inner: false,
                 };
 
@@ -538,7 +540,8 @@ mod tests {
                 // the first one should be a macro_rules
                 let def = MacroDefId {
                     krate,
-                    kind: MacroDefKind::BuiltInEager(expander, ast_id),
+                    ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(&macro_rules))),
+                    kind: MacroDefKind::BuiltInEager(expander),
                     local_inner: false,
                 };
 
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs
index 2748e25cf3..a3070f1f94 100644
--- a/crates/hir_expand/src/db.rs
+++ b/crates/hir_expand/src/db.rs
@@ -130,8 +130,8 @@ fn ast_id_map(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<AstIdMap> {
 
 fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>> {
     match id.kind {
-        MacroDefKind::Declarative(ast_id) => {
-            let macro_rules = match ast_id.to_node(db) {
+        MacroDefKind::Declarative => {
+            let macro_rules = match id.ast_id?.to_node(db) {
                 syntax::ast::Macro::MacroRules(mac) => mac,
                 syntax::ast::Macro::MacroDef(_) => return None,
             };
@@ -150,14 +150,14 @@ fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option<Arc<(TokenExpander,
             };
             Some(Arc::new((TokenExpander::MacroRules(rules), tmap)))
         }
-        MacroDefKind::BuiltIn(expander, _) => {
+        MacroDefKind::BuiltIn(expander) => {
             Some(Arc::new((TokenExpander::Builtin(expander), mbe::TokenMap::default())))
         }
-        MacroDefKind::BuiltInDerive(expander, _) => {
+        MacroDefKind::BuiltInDerive(expander) => {
             Some(Arc::new((TokenExpander::BuiltinDerive(expander), mbe::TokenMap::default())))
         }
-        MacroDefKind::BuiltInEager(..) => None,
-        MacroDefKind::ProcMacro(expander, ..) => {
+        MacroDefKind::BuiltInEager(_) => None,
+        MacroDefKind::ProcMacro(expander) => {
             Some(Arc::new((TokenExpander::ProcMacro(expander), mbe::TokenMap::default())))
         }
     }
@@ -269,7 +269,7 @@ fn expand_proc_macro(
     };
 
     let expander = match loc.def.kind {
-        MacroDefKind::ProcMacro(expander, ..) => expander,
+        MacroDefKind::ProcMacro(expander) => expander,
         _ => unreachable!(),
     };
 
diff --git a/crates/hir_expand/src/eager.rs b/crates/hir_expand/src/eager.rs
index 04f374a29f..dc618a9ee1 100644
--- a/crates/hir_expand/src/eager.rs
+++ b/crates/hir_expand/src/eager.rs
@@ -140,7 +140,7 @@ pub fn expand_eager_macro(
     let subtree =
         diagnostic_sink.option(to_subtree(&result), || err("failed to parse macro result"))?;
 
-    if let MacroDefKind::BuiltInEager(eager, _) = def.kind {
+    if let MacroDefKind::BuiltInEager(eager) = def.kind {
         let res = eager.expand(db, arg_id, &subtree);
 
         let (subtree, fragment) = diagnostic_sink.expand_result_option(res)?;
@@ -193,7 +193,7 @@ fn eager_macro_recur(
         let def = diagnostic_sink
             .option_with(|| macro_resolver(child.path()?), || err("failed to resolve macro"))?;
         let insert = match def.kind {
-            MacroDefKind::BuiltInEager(..) => {
+            MacroDefKind::BuiltInEager(_) => {
                 let id: MacroCallId = expand_eager_macro(
                     db,
                     krate,
@@ -206,10 +206,10 @@ fn eager_macro_recur(
                 db.parse_or_expand(id.as_file())
                     .expect("successful macro expansion should be parseable")
             }
-            MacroDefKind::Declarative(_)
-            | MacroDefKind::BuiltIn(..)
-            | MacroDefKind::BuiltInDerive(..)
-            | MacroDefKind::ProcMacro(..) => {
+            MacroDefKind::Declarative
+            | MacroDefKind::BuiltIn(_)
+            | MacroDefKind::BuiltInDerive(_)
+            | MacroDefKind::ProcMacro(_) => {
                 let res = lazy_expand(db, &def, curr.with_value(child.clone()), krate);
                 let val = diagnostic_sink.expand_result_option(res)?;
 
diff --git a/crates/hir_expand/src/hygiene.rs b/crates/hir_expand/src/hygiene.rs
index 20cda1683a..87cad326d1 100644
--- a/crates/hir_expand/src/hygiene.rs
+++ b/crates/hir_expand/src/hygiene.rs
@@ -145,7 +145,7 @@ fn make_hygiene_info(
 ) -> Option<HygieneInfo> {
     let arg_tt = loc.kind.arg(db)?;
 
-    let def_offset = loc.def.ast_id().and_then(|id| {
+    let def_offset = loc.def.ast_id.and_then(|id| {
         let def_tt = match id.to_node(db) {
             ast::Macro::MacroRules(mac) => mac.token_tree()?.syntax().text_range().start(),
             ast::Macro::MacroDef(_) => return None,
@@ -176,13 +176,13 @@ impl HygieneFrame {
                     let loc = db.lookup_intern_macro(id);
                     let info = make_hygiene_info(db, macro_file, &loc);
                     match loc.def.kind {
-                        MacroDefKind::Declarative(_) => {
+                        MacroDefKind::Declarative => {
                             (info, Some(loc.def.krate), loc.def.local_inner)
                         }
-                        MacroDefKind::BuiltIn(..) => (info, Some(loc.def.krate), false),
-                        MacroDefKind::BuiltInDerive(..) => (info, None, false),
-                        MacroDefKind::BuiltInEager(..) => (info, None, false),
-                        MacroDefKind::ProcMacro(..) => (info, None, false),
+                        MacroDefKind::BuiltIn(_) => (info, Some(loc.def.krate), false),
+                        MacroDefKind::BuiltInDerive(_) => (info, None, false),
+                        MacroDefKind::BuiltInEager(_) => (info, None, false),
+                        MacroDefKind::ProcMacro(_) => (info, None, false),
                     }
                 }
             },
diff --git a/crates/hir_expand/src/lib.rs b/crates/hir_expand/src/lib.rs
index 0a379651f0..7532d00b83 100644
--- a/crates/hir_expand/src/lib.rs
+++ b/crates/hir_expand/src/lib.rs
@@ -143,7 +143,7 @@ impl HirFileId {
 
                 let arg_tt = loc.kind.arg(db)?;
 
-                let def = loc.def.ast_id().and_then(|id| {
+                let def = loc.def.ast_id.and_then(|id| {
                     let def_tt = match id.to_node(db) {
                         ast::Macro::MacroRules(mac) => mac.token_tree()?,
                         ast::Macro::MacroDef(_) => return None,
@@ -180,7 +180,7 @@ impl HirFileId {
                 };
                 let loc: MacroCallLoc = db.lookup_intern_macro(lazy_id);
                 let item = match loc.def.kind {
-                    MacroDefKind::BuiltInDerive(..) => loc.kind.node(db),
+                    MacroDefKind::BuiltInDerive(_) => loc.kind.node(db),
                     _ => return None,
                 };
                 Some(item.with_value(ast::Item::cast(item.value.clone())?))
@@ -224,6 +224,7 @@ impl From<EagerMacroId> for MacroCallId {
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct MacroDefId {
     pub krate: CrateId,
+    pub ast_id: Option<AstId<ast::Macro>>,
     pub kind: MacroDefKind,
 
     pub local_inner: bool,
@@ -238,27 +239,16 @@ impl MacroDefId {
     ) -> LazyMacroId {
         db.intern_macro(MacroCallLoc { def: self, krate, kind })
     }
-
-    pub fn ast_id(&self) -> Option<AstId<ast::Macro>> {
-        let id = match &self.kind {
-            MacroDefKind::Declarative(id) => id,
-            MacroDefKind::BuiltIn(_, id) => id,
-            MacroDefKind::BuiltInDerive(_, id) => id,
-            MacroDefKind::BuiltInEager(_, id) => id,
-            MacroDefKind::ProcMacro(..) => return None,
-        };
-        Some(*id)
-    }
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub enum MacroDefKind {
-    Declarative(AstId<ast::Macro>),
-    BuiltIn(BuiltinFnLikeExpander, AstId<ast::Macro>),
+    Declarative,
+    BuiltIn(BuiltinFnLikeExpander),
     // FIXME: maybe just Builtin and rename BuiltinFnLikeExpander to BuiltinExpander
-    BuiltInDerive(BuiltinDeriveExpander, AstId<ast::Macro>),
-    BuiltInEager(EagerExpander, AstId<ast::Macro>),
-    ProcMacro(ProcMacroExpander, AstId<ast::Fn>),
+    BuiltInDerive(BuiltinDeriveExpander),
+    BuiltInEager(EagerExpander),
+    ProcMacro(ProcMacroExpander),
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
diff --git a/crates/hir_ty/src/autoderef.rs b/crates/hir_ty/src/autoderef.rs
index ad4e6f23bb..bd2ff5d38a 100644
--- a/crates/hir_ty/src/autoderef.rs
+++ b/crates/hir_ty/src/autoderef.rs
@@ -12,7 +12,7 @@ use log::{info, warn};
 
 use crate::{
     db::HirDatabase,
-    to_assoc_type_id, to_chalk_trait_id,
+    to_assoc_type_id,
     traits::{InEnvironment, Solution},
     utils::generics,
     BoundVar, Canonical, DebruijnIndex, Interner, Obligation, Substitution, TraitRef, Ty, TyKind,
@@ -68,8 +68,7 @@ fn deref_by_trait(
         Substitution::build_for_generics(&generic_params).push(ty.value.value.clone()).build();
 
     // Check that the type implements Deref at all
-    let trait_ref =
-        TraitRef { trait_id: to_chalk_trait_id(deref_trait), substitution: parameters.clone() };
+    let trait_ref = TraitRef { trait_: deref_trait, substs: parameters.clone() };
     let implements_goal = Canonical {
         kinds: ty.value.kinds.clone(),
         value: InEnvironment {
diff --git a/crates/hir_ty/src/diagnostics/decl_check.rs b/crates/hir_ty/src/diagnostics/decl_check.rs
index 33a0f4d7d4..bfe239793c 100644
--- a/crates/hir_ty/src/diagnostics/decl_check.rs
+++ b/crates/hir_ty/src/diagnostics/decl_check.rs
@@ -102,7 +102,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
         let db = self.db;
         for block_def_map in body.block_scopes.iter().filter_map(|block| db.block_def_map(*block)) {
             for (_, module) in block_def_map.modules() {
-                for def_id in module.scope.declarations() {
+                for (def_id, _) in module.scope.values() {
                     let mut validator = DeclValidator::new(self.db, self.krate, self.sink);
                     validator.validate_item(def_id);
                 }
@@ -902,17 +902,4 @@ extern {
             "#,
         );
     }
-
-    #[test]
-    fn infinite_loop_inner_items() {
-        check_diagnostics(
-            r#"
-fn qualify() {
-    mod foo {
-        use super::*;
-    }
-}
-            "#,
-        )
-    }
 }
diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs
index c6b4f37e58..7ce0f864c7 100644
--- a/crates/hir_ty/src/display.rs
+++ b/crates/hir_ty/src/display.rs
@@ -344,7 +344,7 @@ impl HirDisplay for Ty {
                 };
 
                 if let [GenericPredicate::Implemented(trait_ref), _] = predicates.as_ref() {
-                    let trait_ = trait_ref.hir_trait_id();
+                    let trait_ = trait_ref.trait_;
                     if fn_traits(f.db.upcast(), trait_).any(|it| it == trait_) {
                         return write!(f, "{}", ty_display);
                     }
@@ -670,7 +670,7 @@ fn write_bounds_like_dyn_trait(
     for p in predicates.iter() {
         match p {
             GenericPredicate::Implemented(trait_ref) => {
-                let trait_ = trait_ref.hir_trait_id();
+                let trait_ = trait_ref.trait_;
                 if !is_fn_trait {
                     is_fn_trait = fn_traits(f.db.upcast(), trait_).any(|it| it == trait_);
                 }
@@ -685,7 +685,7 @@ fn write_bounds_like_dyn_trait(
                 // existential) here, which is the only thing that's
                 // possible in actual Rust, and hence don't print it
                 write!(f, "{}", f.db.trait_data(trait_).name)?;
-                if let [_, params @ ..] = &*trait_ref.substitution.0 {
+                if let [_, params @ ..] = &*trait_ref.substs.0 {
                     if is_fn_trait {
                         if let Some(args) = params.first().and_then(|it| it.as_tuple()) {
                             write!(f, "(")?;
@@ -745,16 +745,16 @@ impl TraitRef {
             return write!(f, "{}", TYPE_HINT_TRUNCATION);
         }
 
-        self.substitution[0].hir_fmt(f)?;
+        self.substs[0].hir_fmt(f)?;
         if use_as {
             write!(f, " as ")?;
         } else {
             write!(f, ": ")?;
         }
-        write!(f, "{}", f.db.trait_data(self.hir_trait_id()).name)?;
-        if self.substitution.len() > 1 {
+        write!(f, "{}", f.db.trait_data(self.trait_).name)?;
+        if self.substs.len() > 1 {
             write!(f, "<")?;
-            f.write_joined(&self.substitution[1..], ", ")?;
+            f.write_joined(&self.substs[1..], ", ")?;
             write!(f, ">")?;
         }
         Ok(())
diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs
index b6ae4fc655..2610c92795 100644
--- a/crates/hir_ty/src/infer.rs
+++ b/crates/hir_ty/src/infer.rs
@@ -42,7 +42,7 @@ use super::{
 };
 use crate::{
     db::HirDatabase, infer::diagnostics::InferenceDiagnostic, lower::ImplTraitLoweringMode,
-    to_assoc_type_id, to_chalk_trait_id, AliasTy, Interner, TyKind,
+    to_assoc_type_id, AliasTy, Interner, TyKind,
 };
 
 pub(crate) use unify::unify;
@@ -394,8 +394,7 @@ impl<'a> InferenceContext<'a> {
                     .push(inner_ty)
                     .fill(params.iter().cloned())
                     .build();
-                let trait_ref =
-                    TraitRef { trait_id: to_chalk_trait_id(trait_), substitution: substs.clone() };
+                let trait_ref = TraitRef { trait_, substs: substs.clone() };
                 let projection = ProjectionPredicate {
                     ty: ty.clone(),
                     projection_ty: ProjectionTy {
diff --git a/crates/hir_ty/src/infer/coerce.rs b/crates/hir_ty/src/infer/coerce.rs
index b86474ed41..b1f98c507d 100644
--- a/crates/hir_ty/src/infer/coerce.rs
+++ b/crates/hir_ty/src/infer/coerce.rs
@@ -8,8 +8,7 @@ use chalk_ir::{Mutability, TyVariableKind};
 use hir_def::lang_item::LangItemTarget;
 
 use crate::{
-    autoderef, to_chalk_trait_id, traits::Solution, Interner, Obligation, Substitution, TraitRef,
-    Ty, TyKind,
+    autoderef, traits::Solution, Interner, Obligation, Substitution, TraitRef, Ty, TyKind,
 };
 
 use super::{InEnvironment, InferenceContext};
@@ -141,8 +140,7 @@ impl<'a> InferenceContext<'a> {
             .push(from_ty.clone())
             .push(to_ty.clone())
             .build();
-        let trait_ref =
-            TraitRef { trait_id: to_chalk_trait_id(coerce_unsized_trait), substitution: substs };
+        let trait_ref = TraitRef { trait_: coerce_unsized_trait, substs };
         let goal = InEnvironment::new(self.trait_env.clone(), Obligation::Trait(trait_ref));
 
         let canonicalizer = self.canonicalizer();
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index 93548b6c02..0be8c5a902 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -18,7 +18,7 @@ use crate::{
     lower::lower_to_chalk_mutability,
     method_resolution, op,
     primitive::{self, UintTy},
-    to_assoc_type_id, to_chalk_trait_id,
+    to_assoc_type_id,
     traits::{chalk::from_chalk, FnTrait, InEnvironment},
     utils::{generics, variant_data, Generics},
     AdtId, Binders, CallableDefId, FnPointer, FnSig, Interner, Obligation, Rawness, Scalar,
@@ -90,10 +90,8 @@ impl<'a> InferenceContext<'a> {
             Substitution::build_for_generics(&generic_params).push(ty.clone()).push(arg_ty).build();
 
         let trait_env = Arc::clone(&self.trait_env);
-        let implements_fn_trait = Obligation::Trait(TraitRef {
-            trait_id: to_chalk_trait_id(fn_once_trait),
-            substitution: substs.clone(),
-        });
+        let implements_fn_trait =
+            Obligation::Trait(TraitRef { trait_: fn_once_trait, substs: substs.clone() });
         let goal = self.canonicalizer().canonicalize_obligation(InEnvironment {
             value: implements_fn_trait.clone(),
             environment: trait_env,
@@ -950,10 +948,7 @@ impl<'a> InferenceContext<'a> {
                         // construct a TraitDef
                         let substs =
                             parameters.prefix(generics(self.db.upcast(), trait_.into()).len());
-                        self.obligations.push(Obligation::Trait(TraitRef {
-                            trait_id: to_chalk_trait_id(trait_),
-                            substitution: substs,
-                        }));
+                        self.obligations.push(Obligation::Trait(TraitRef { trait_, substs }));
                     }
                 }
                 CallableDefId::StructId(_) | CallableDefId::EnumVariantId(_) => {}
diff --git a/crates/hir_ty/src/infer/path.rs b/crates/hir_ty/src/infer/path.rs
index e15135fc1f..ea01d62387 100644
--- a/crates/hir_ty/src/infer/path.rs
+++ b/crates/hir_ty/src/infer/path.rs
@@ -9,9 +9,7 @@ use hir_def::{
 };
 use hir_expand::name::Name;
 
-use crate::{
-    method_resolution, to_chalk_trait_id, Interner, Substitution, Ty, TyKind, ValueTyDefId,
-};
+use crate::{method_resolution, Interner, Substitution, Ty, TyKind, ValueTyDefId};
 
 use super::{ExprOrPatId, InferenceContext, TraitRef};
 
@@ -167,7 +165,7 @@ impl<'a> InferenceContext<'a> {
         segment: PathSegment<'_>,
         id: ExprOrPatId,
     ) -> Option<(ValueNs, Option<Substitution>)> {
-        let trait_ = trait_ref.hir_trait_id();
+        let trait_ = trait_ref.trait_;
         let item =
             self.db.trait_data(trait_).items.iter().map(|(_name, id)| (*id)).find_map(|item| {
                 match item {
@@ -202,7 +200,7 @@ impl<'a> InferenceContext<'a> {
         };
 
         self.write_assoc_resolution(id, item);
-        Some((def, Some(trait_ref.substitution)))
+        Some((def, Some(trait_ref.substs)))
     }
 
     fn resolve_ty_assoc_item(
@@ -257,8 +255,8 @@ impl<'a> InferenceContext<'a> {
                             .fill(std::iter::repeat_with(|| self.table.new_type_var()))
                             .build();
                         self.obligations.push(super::Obligation::Trait(TraitRef {
-                            trait_id: to_chalk_trait_id(trait_),
-                            substitution: trait_substs.clone(),
+                            trait_,
+                            substs: trait_substs.clone(),
                         }));
                         Some(trait_substs)
                     }
diff --git a/crates/hir_ty/src/infer/unify.rs b/crates/hir_ty/src/infer/unify.rs
index f5ea096982..b2d4f67b31 100644
--- a/crates/hir_ty/src/infer/unify.rs
+++ b/crates/hir_ty/src/infer/unify.rs
@@ -390,9 +390,9 @@ impl InferenceTable {
     ) -> bool {
         match (pred1, pred2) {
             (GenericPredicate::Implemented(tr1), GenericPredicate::Implemented(tr2))
-                if tr1.trait_id == tr2.trait_id =>
+                if tr1.trait_ == tr2.trait_ =>
             {
-                self.unify_substs(&tr1.substitution, &tr2.substitution, depth + 1)
+                self.unify_substs(&tr1.substs, &tr2.substs, depth + 1)
             }
             (GenericPredicate::Projection(proj1), GenericPredicate::Projection(proj2))
                 if proj1.projection_ty.associated_ty_id == proj2.projection_ty.associated_ty_id =>
diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs
index 3859dbfa14..52b498ff70 100644
--- a/crates/hir_ty/src/lib.rs
+++ b/crates/hir_ty/src/lib.rs
@@ -58,8 +58,6 @@ pub type ClosureId = chalk_ir::ClosureId<Interner>;
 pub type OpaqueTyId = chalk_ir::OpaqueTyId<Interner>;
 pub type PlaceholderIndex = chalk_ir::PlaceholderIndex;
 
-pub type ChalkTraitId = chalk_ir::TraitId<Interner>;
-
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
 pub enum Lifetime {
     Parameter(LifetimeParamId),
@@ -83,10 +81,7 @@ pub struct ProjectionTy {
 
 impl ProjectionTy {
     pub fn trait_ref(&self, db: &dyn HirDatabase) -> TraitRef {
-        TraitRef {
-            trait_id: to_chalk_trait_id(self.trait_(db)),
-            substitution: self.substitution.clone(),
-        }
+        TraitRef { trait_: self.trait_(db), substs: self.substitution.clone() }
     }
 
     fn trait_(&self, db: &dyn HirDatabase) -> TraitId {
@@ -498,25 +493,23 @@ impl<T: TypeWalk> TypeWalk for Binders<T> {
 }
 
 /// A trait with type parameters. This includes the `Self`, so this represents a concrete type implementing the trait.
+/// Name to be bikeshedded: TraitBound? TraitImplements?
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
 pub struct TraitRef {
-    pub trait_id: ChalkTraitId,
-    pub substitution: Substitution,
+    /// FIXME name?
+    pub trait_: TraitId,
+    pub substs: Substitution,
 }
 
 impl TraitRef {
-    pub fn self_type_parameter(&self) -> &Ty {
-        &self.substitution[0]
-    }
-
-    pub fn hir_trait_id(&self) -> TraitId {
-        from_chalk_trait_id(self.trait_id)
+    pub fn self_ty(&self) -> &Ty {
+        &self.substs[0]
     }
 }
 
 impl TypeWalk for TraitRef {
     fn walk(&self, f: &mut impl FnMut(&Ty)) {
-        self.substitution.walk(f);
+        self.substs.walk(f);
     }
 
     fn walk_mut_binders(
@@ -524,7 +517,7 @@ impl TypeWalk for TraitRef {
         f: &mut impl FnMut(&mut Ty, DebruijnIndex),
         binders: DebruijnIndex,
     ) {
-        self.substitution.walk_mut_binders(f, binders);
+        self.substs.walk_mut_binders(f, binders);
     }
 }
 
@@ -791,7 +784,7 @@ impl Ty {
 
     /// If this is a `dyn Trait`, returns that trait.
     pub fn dyn_trait(&self) -> Option<TraitId> {
-        self.dyn_trait_ref().map(|it| it.trait_id).map(from_chalk_trait_id)
+        self.dyn_trait_ref().map(|it| it.trait_)
     }
 
     fn builtin_deref(&self) -> Option<Ty> {
@@ -875,8 +868,8 @@ impl Ty {
                             // Parameters will be walked outside, and projection predicate is not used.
                             // So just provide the Future trait.
                             let impl_bound = GenericPredicate::Implemented(TraitRef {
-                                trait_id: to_chalk_trait_id(future_trait),
-                                substitution: Substitution::empty(),
+                                trait_: future_trait,
+                                substs: Substitution::empty(),
                             });
                             Some(vec![impl_bound])
                         } else {
@@ -1165,11 +1158,3 @@ pub fn to_placeholder_idx(db: &dyn HirDatabase, id: TypeParamId) -> PlaceholderI
         idx: salsa::InternKey::as_intern_id(&interned_id).as_usize(),
     }
 }
-
-pub fn to_chalk_trait_id(id: TraitId) -> ChalkTraitId {
-    chalk_ir::TraitId(salsa::InternKey::as_intern_id(&id))
-}
-
-pub fn from_chalk_trait_id(id: ChalkTraitId) -> TraitId {
-    salsa::InternKey::from_intern_id(id.0)
-}
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs
index 5d950a0175..462882b2b3 100644
--- a/crates/hir_ty/src/lower.rs
+++ b/crates/hir_ty/src/lower.rs
@@ -27,7 +27,7 @@ use stdx::impl_from;
 
 use crate::{
     db::HirDatabase,
-    to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx,
+    to_assoc_type_id, to_placeholder_idx,
     traits::chalk::{Interner, ToChalk},
     utils::{
         all_super_trait_refs, associated_type_by_name_including_super_traits, generics,
@@ -360,7 +360,7 @@ impl<'a> TyLoweringContext<'a> {
                             // FIXME handle type parameters on the segment
                             TyKind::Alias(AliasTy::Projection(ProjectionTy {
                                 associated_ty_id: to_assoc_type_id(associated_ty),
-                                substitution: super_trait_ref.substitution,
+                                substitution: super_trait_ref.substs,
                             }))
                             .intern(&Interner)
                         }
@@ -470,9 +470,9 @@ impl<'a> TyLoweringContext<'a> {
                                         "there should be generics if there's a generic param",
                                     ),
                                 );
-                                t.substitution.clone().subst_bound_vars(&s)
+                                t.substs.clone().subst_bound_vars(&s)
                             }
-                            TypeParamLoweringMode::Variable => t.substitution.clone(),
+                            TypeParamLoweringMode::Variable => t.substs.clone(),
                         };
                         // We need to shift in the bound vars, since
                         // associated_type_shorthand_candidates does not do that
@@ -641,7 +641,7 @@ impl<'a> TyLoweringContext<'a> {
         if let Some(self_ty) = explicit_self_ty {
             substs.0[0] = self_ty;
         }
-        TraitRef { trait_id: to_chalk_trait_id(resolved), substitution: substs }
+        TraitRef { trait_: resolved, substs }
     }
 
     fn lower_trait_ref(
@@ -743,7 +743,7 @@ impl<'a> TyLoweringContext<'a> {
                 };
                 let projection_ty = ProjectionTy {
                     associated_ty_id: to_assoc_type_id(associated_ty),
-                    substitution: super_trait_ref.substitution,
+                    substitution: super_trait_ref.substs,
                 };
                 let mut preds = SmallVec::with_capacity(
                     binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(),
@@ -820,8 +820,8 @@ pub fn associated_type_shorthand_candidates<R>(
                     == TypeParamProvenance::TraitSelf
                 {
                     let trait_ref = TraitRef {
-                        trait_id: to_chalk_trait_id(trait_id),
-                        substitution: Substitution::bound_vars(&generics, DebruijnIndex::INNERMOST),
+                        trait_: trait_id,
+                        substs: Substitution::bound_vars(&generics, DebruijnIndex::INNERMOST),
                     };
                     traits_.push(trait_ref);
                 }
@@ -832,7 +832,7 @@ pub fn associated_type_shorthand_candidates<R>(
     };
 
     for t in traits_from_env.into_iter().flat_map(move |t| all_super_trait_refs(db, t)) {
-        let data = db.trait_data(t.hir_trait_id());
+        let data = db.trait_data(t.trait_);
 
         for (name, assoc_id) in &data.items {
             match assoc_id {
@@ -926,7 +926,7 @@ pub(crate) fn trait_environment_query(
                 continue;
             }
             if let GenericPredicate::Implemented(tr) = &pred {
-                traits_in_scope.push((tr.self_type_parameter().clone(), tr.hir_trait_id()));
+                traits_in_scope.push((tr.self_ty().clone(), tr.trait_));
             }
             let program_clause: chalk_ir::ProgramClause<Interner> =
                 pred.clone().to_chalk(db).cast(&Interner);
@@ -950,7 +950,7 @@ pub(crate) fn trait_environment_query(
         // inside consts or type aliases)
         cov_mark::hit!(trait_self_implements_self);
         let substs = Substitution::type_params(db, trait_id);
-        let trait_ref = TraitRef { trait_id: to_chalk_trait_id(trait_id), substitution: substs };
+        let trait_ref = TraitRef { trait_: trait_id, substs };
         let pred = GenericPredicate::Implemented(trait_ref);
         let program_clause: chalk_ir::ProgramClause<Interner> =
             pred.clone().to_chalk(db).cast(&Interner);
diff --git a/crates/hir_ty/src/method_resolution.rs b/crates/hir_ty/src/method_resolution.rs
index 01b78fb445..943d3339b3 100644
--- a/crates/hir_ty/src/method_resolution.rs
+++ b/crates/hir_ty/src/method_resolution.rs
@@ -19,7 +19,6 @@ use crate::{
     db::HirDatabase,
     from_foreign_def_id,
     primitive::{self, FloatTy, IntTy, UintTy},
-    to_chalk_trait_id,
     utils::all_super_traits,
     AdtId, Canonical, DebruijnIndex, FnPointer, FnSig, ForeignDefId, InEnvironment, Interner,
     Scalar, Substitution, TraitEnvironment, TraitRef, Ty, TyKind, TypeWalk,
@@ -102,7 +101,7 @@ impl TraitImpls {
         for (_module_id, module_data) in crate_def_map.modules() {
             for impl_id in module_data.scope.impls() {
                 let target_trait = match db.impl_trait(impl_id) {
-                    Some(tr) => tr.value.hir_trait_id(),
+                    Some(tr) => tr.value.trait_,
                     None => continue,
                 };
                 let self_ty = db.impl_self_ty(impl_id);
@@ -774,7 +773,7 @@ fn generic_implements_goal(
         .fill_with_bound_vars(DebruijnIndex::INNERMOST, kinds.len())
         .build();
     kinds.extend(iter::repeat(chalk_ir::TyVariableKind::General).take(substs.len() - 1));
-    let trait_ref = TraitRef { trait_id: to_chalk_trait_id(trait_), substitution: substs };
+    let trait_ref = TraitRef { trait_, substs };
     let obligation = super::Obligation::Trait(trait_ref);
     Canonical { kinds: kinds.into(), value: InEnvironment::new(env, obligation) }
 }
diff --git a/crates/hir_ty/src/traits.rs b/crates/hir_ty/src/traits.rs
index a7287dea1c..40eb1034ec 100644
--- a/crates/hir_ty/src/traits.rs
+++ b/crates/hir_ty/src/traits.rs
@@ -137,7 +137,7 @@ pub(crate) fn trait_solve_query(
     goal: Canonical<InEnvironment<Obligation>>,
 ) -> Option<Solution> {
     let _p = profile::span("trait_solve_query").detail(|| match &goal.value.value {
-        Obligation::Trait(it) => db.trait_data(it.hir_trait_id()).name.to_string(),
+        Obligation::Trait(it) => db.trait_data(it.trait_).name.to_string(),
         Obligation::Projection(_) => "projection".to_string(),
     });
     log::info!("trait_solve_query({})", goal.value.value.display(db));
diff --git a/crates/hir_ty/src/traits/chalk.rs b/crates/hir_ty/src/traits/chalk.rs
index bac70f5aa4..bef6e7e9c0 100644
--- a/crates/hir_ty/src/traits/chalk.rs
+++ b/crates/hir_ty/src/traits/chalk.rs
@@ -19,7 +19,7 @@ use crate::{
     display::HirDisplay,
     from_assoc_type_id,
     method_resolution::{TyFingerprint, ALL_FLOAT_FPS, ALL_INT_FPS},
-    to_assoc_type_id, to_chalk_trait_id,
+    to_assoc_type_id,
     utils::generics,
     BoundVar, CallableDefId, CallableSig, DebruijnIndex, FnDefId, GenericPredicate,
     ProjectionPredicate, ProjectionTy, Substitution, TraitRef, Ty, TyKind,
@@ -219,9 +219,9 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
                     // for<T> <Self> [Future<Self>, Future::Output<Self> = T]
                     //     ^1  ^0            ^0                    ^0      ^1
                     let impl_bound = GenericPredicate::Implemented(TraitRef {
-                        trait_id: to_chalk_trait_id(future_trait),
+                        trait_: future_trait,
                         // Self type as the first parameter.
-                        substitution: Substitution::single(
+                        substs: Substitution::single(
                             TyKind::BoundVar(BoundVar {
                                 debruijn: DebruijnIndex::INNERMOST,
                                 index: 0,
@@ -546,7 +546,7 @@ fn impl_def_datum(
 
     let generic_params = generics(db.upcast(), impl_id.into());
     let bound_vars = Substitution::bound_vars(&generic_params, DebruijnIndex::INNERMOST);
-    let trait_ = trait_ref.hir_trait_id();
+    let trait_ = trait_ref.trait_;
     let impl_type = if impl_id.lookup(db.upcast()).container.krate() == krate {
         rust_ir::ImplType::Local
     } else {
@@ -614,7 +614,7 @@ fn type_alias_associated_ty_value(
     let trait_ref = db.impl_trait(impl_id).expect("assoc ty value should not exist").value; // we don't return any assoc ty values if the impl'd trait can't be resolved
 
     let assoc_ty = db
-        .trait_data(trait_ref.hir_trait_id())
+        .trait_data(trait_ref.trait_)
         .associated_type_by_name(&type_alias_data.name)
         .expect("assoc ty value should not exist"); // validated when building the impl data as well
     let ty = db.ty(type_alias.into());
diff --git a/crates/hir_ty/src/traits/chalk/mapping.rs b/crates/hir_ty/src/traits/chalk/mapping.rs
index 0086ce1e9d..d969527dc9 100644
--- a/crates/hir_ty/src/traits/chalk/mapping.rs
+++ b/crates/hir_ty/src/traits/chalk/mapping.rs
@@ -239,15 +239,15 @@ impl ToChalk for TraitRef {
     type Chalk = chalk_ir::TraitRef<Interner>;
 
     fn to_chalk(self: TraitRef, db: &dyn HirDatabase) -> chalk_ir::TraitRef<Interner> {
-        let trait_id = self.trait_id;
-        let substitution = self.substitution.to_chalk(db);
+        let trait_id = self.trait_.to_chalk(db);
+        let substitution = self.substs.to_chalk(db);
         chalk_ir::TraitRef { trait_id, substitution }
     }
 
     fn from_chalk(db: &dyn HirDatabase, trait_ref: chalk_ir::TraitRef<Interner>) -> Self {
-        let trait_id = trait_ref.trait_id;
+        let trait_ = from_chalk(db, trait_ref.trait_id);
         let substs = from_chalk(db, trait_ref.substitution);
-        TraitRef { trait_id, substitution: substs }
+        TraitRef { trait_, substs }
     }
 }
 
@@ -515,16 +515,17 @@ pub(super) fn generic_predicate_to_inline_bound(
     // We don't have a special type for this, but Chalk does.
     match pred {
         GenericPredicate::Implemented(trait_ref) => {
-            if &trait_ref.substitution[0] != self_ty {
+            if &trait_ref.substs[0] != self_ty {
                 // we can only convert predicates back to type bounds if they
                 // have the expected self type
                 return None;
             }
-            let args_no_self = trait_ref.substitution[1..]
+            let args_no_self = trait_ref.substs[1..]
                 .iter()
                 .map(|ty| ty.clone().to_chalk(db).cast(&Interner))
                 .collect();
-            let trait_bound = rust_ir::TraitBound { trait_id: trait_ref.trait_id, args_no_self };
+            let trait_bound =
+                rust_ir::TraitBound { trait_id: trait_ref.trait_.to_chalk(db), args_no_self };
             Some(rust_ir::InlineBound::TraitBound(trait_bound))
         }
         GenericPredicate::Projection(proj) => {
diff --git a/crates/hir_ty/src/utils.rs b/crates/hir_ty/src/utils.rs
index b66243d488..7351e4e54a 100644
--- a/crates/hir_ty/src/utils.rs
+++ b/crates/hir_ty/src/utils.rs
@@ -55,9 +55,9 @@ fn direct_super_trait_refs(db: &dyn HirDatabase, trait_ref: &TraitRef) -> Vec<Tr
     // lifetime problems, but since there usually shouldn't be more than a
     // few direct traits this should be fine (we could even use some kind of
     // SmallVec if performance is a concern)
-    let generic_params = db.generic_params(trait_ref.hir_trait_id().into());
+    let generic_params = db.generic_params(trait_ref.trait_.into());
     let trait_self = match generic_params.find_trait_self_param() {
-        Some(p) => TypeParamId { parent: trait_ref.hir_trait_id().into(), local_id: p },
+        Some(p) => TypeParamId { parent: trait_ref.trait_.into(), local_id: p },
         None => return Vec::new(),
     };
     db.generic_predicates_for_param(trait_self)
@@ -68,7 +68,7 @@ fn direct_super_trait_refs(db: &dyn HirDatabase, trait_ref: &TraitRef) -> Vec<Tr
                 _ => None,
             })
         })
-        .map(|pred| pred.subst(&trait_ref.substitution))
+        .map(|pred| pred.subst(&trait_ref.substs))
         .collect()
 }
 
@@ -108,7 +108,7 @@ pub(super) fn all_super_trait_refs(db: &dyn HirDatabase, trait_ref: TraitRef) ->
         // yeah this is quadratic, but trait hierarchies should be flat
         // enough that this doesn't matter
         for tt in direct_super_trait_refs(db, t) {
-            if !result.iter().any(|tr| tr.trait_id == tt.trait_id) {
+            if !result.iter().any(|tr| tr.trait_ == tt.trait_) {
                 result.push(tt);
             }
         }
@@ -123,7 +123,7 @@ pub(super) fn associated_type_by_name_including_super_traits(
     name: &Name,
 ) -> Option<(TraitRef, TypeAliasId)> {
     all_super_trait_refs(db, trait_ref).into_iter().find_map(|t| {
-        let assoc_type = db.trait_data(t.hir_trait_id()).associated_type_by_name(name)?;
+        let assoc_type = db.trait_data(t.trait_).associated_type_by_name(name)?;
         Some((t, assoc_type))
     })
 }
diff --git a/crates/ide/src/display/navigation_target.rs b/crates/ide/src/display/navigation_target.rs
index 364be260c6..c086de163f 100644
--- a/crates/ide/src/display/navigation_target.rs
+++ b/crates/ide/src/display/navigation_target.rs
@@ -339,14 +339,10 @@ impl TryToNav for hir::Field {
 impl TryToNav for hir::MacroDef {
     fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
         let src = self.source(db)?;
-        let name_owner: &dyn ast::NameOwner = match &src.value {
-            Either::Left(it) => it,
-            Either::Right(it) => it,
-        };
-        log::debug!("nav target {:#?}", name_owner.syntax());
+        log::debug!("nav target {:#?}", src.value.syntax());
         let mut res = NavigationTarget::from_named(
             db,
-            src.as_ref().with_value(name_owner),
+            src.as_ref().map(|it| it as &dyn ast::NameOwner),
             SymbolKind::Macro,
         );
         res.docs = self.docs(db);
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs
index 473d48c2fc..598b47e417 100644
--- a/crates/ide/src/goto_definition.rs
+++ b/crates/ide/src/goto_definition.rs
@@ -1176,21 +1176,4 @@ fn foo() { A { a$0: }; }
 "#,
         )
     }
-
-    #[test]
-    fn goto_proc_macro() {
-        check(
-            r#"
-//- /main.rs crate:main deps:mac
-use mac::fn_macro;
-
-fn_macro$0!();
-
-//- /mac.rs crate:mac
-#[proc_macro]
-fn fn_macro() {}
- //^^^^^^^^
-            "#,
-        )
-    }
 }
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index a3fb17c0a6..15d309d7d6 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -331,16 +331,10 @@ fn hover_for_definition(
 ) -> Option<Markup> {
     let mod_path = definition_mod_path(db, &def);
     return match def {
-        Definition::Macro(it) => match &it.source(db)?.value {
-            Either::Left(mac) => {
-                let label = macro_label(&mac);
-                from_def_source_labeled(db, it, Some(label), mod_path)
-            }
-            Either::Right(_) => {
-                // FIXME
-                None
-            }
-        },
+        Definition::Macro(it) => {
+            let label = macro_label(&it.source(db)?.value);
+            from_def_source_labeled(db, it, Some(label), mod_path)
+        }
         Definition::Field(def) => from_hir_fmt(db, def, mod_path),
         Definition::ModuleDef(it) => match it {
             ModuleDef::Module(it) => from_hir_fmt(db, it, mod_path),
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs
index e25b698e0c..ba3447b3a3 100644
--- a/crates/ide/src/syntax_highlighting.rs
+++ b/crates/ide/src/syntax_highlighting.rs
@@ -12,7 +12,7 @@ mod html;
 #[cfg(test)]
 mod tests;
 
-use hir::{InFile, Name, Semantics};
+use hir::{Name, Semantics};
 use ide_db::{RootDatabase, SymbolKind};
 use rustc_hash::FxHashMap;
 use syntax::{
@@ -73,20 +73,14 @@ pub(crate) fn highlight(
     };
 
     let mut hl = highlights::Highlights::new(root.text_range());
-    traverse(
-        &mut hl,
-        &sema,
-        InFile::new(file_id.into(), &root),
-        range_to_highlight,
-        syntactic_name_ref_highlighting,
-    );
+    traverse(&mut hl, &sema, &root, range_to_highlight, syntactic_name_ref_highlighting);
     hl.to_vec()
 }
 
 fn traverse(
     hl: &mut Highlights,
     sema: &Semantics<RootDatabase>,
-    root: InFile<&SyntaxNode>,
+    root: &SyntaxNode,
     range_to_highlight: TextRange,
     syntactic_name_ref_highlighting: bool,
 ) {
@@ -99,7 +93,7 @@ fn traverse(
 
     // Walk all nodes, keeping track of whether we are inside a macro or not.
     // If in macro, expand it first and highlight the expanded code.
-    for event in root.value.preorder_with_tokens() {
+    for event in root.preorder_with_tokens() {
         let event_range = match &event {
             WalkEvent::Enter(it) | WalkEvent::Leave(it) => it.text_range(),
         };
@@ -156,7 +150,7 @@ fn traverse(
             WalkEvent::Enter(it) => it,
             WalkEvent::Leave(it) => {
                 if let Some(node) = it.as_node() {
-                    inject::doc_comment(hl, sema, root.with_value(node));
+                    inject::doc_comment(hl, sema, node);
                 }
                 continue;
             }
diff --git a/crates/ide/src/syntax_highlighting/html.rs b/crates/ide/src/syntax_highlighting/html.rs
index 5327af845c..1d34731ab9 100644
--- a/crates/ide/src/syntax_highlighting/html.rs
+++ b/crates/ide/src/syntax_highlighting/html.rs
@@ -59,7 +59,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .label              { color: #DFAF8F; font-style: italic; }
 .comment            { color: #7F9F7F; }
 .documentation      { color: #629755; }
-.intra_doc_link     { font-style: italic; }
+.intra_doc_link     { color: #A9C577; }
 .injected           { opacity: 0.65 ; }
 .struct, .enum      { color: #7CB8BB; }
 .enum_variant       { color: #BDE0F3; }
diff --git a/crates/ide/src/syntax_highlighting/inject.rs b/crates/ide/src/syntax_highlighting/inject.rs
index f359eacf2a..90feb6c188 100644
--- a/crates/ide/src/syntax_highlighting/inject.rs
+++ b/crates/ide/src/syntax_highlighting/inject.rs
@@ -3,8 +3,8 @@
 use std::{mem, ops::Range};
 
 use either::Either;
-use hir::{HasAttrs, InFile, Semantics};
-use ide_db::{call_info::ActiveParameter, defs::Definition, SymbolKind};
+use hir::{HasAttrs, Semantics};
+use ide_db::{call_info::ActiveParameter, defs::Definition};
 use syntax::{
     ast::{self, AstNode, AttrsOwner, DocCommentsOwner},
     match_ast, AstToken, NodeOrToken, SyntaxNode, SyntaxToken, TextRange, TextSize,
@@ -148,12 +148,8 @@ fn doc_attributes<'node>(
 }
 
 /// Injection of syntax highlighting of doctests.
-pub(super) fn doc_comment(
-    hl: &mut Highlights,
-    sema: &Semantics<RootDatabase>,
-    node: InFile<&SyntaxNode>,
-) {
-    let (owner, attributes, def) = match doc_attributes(sema, node.value) {
+pub(super) fn doc_comment(hl: &mut Highlights, sema: &Semantics<RootDatabase>, node: &SyntaxNode) {
+    let (owner, attributes, def) = match doc_attributes(sema, node) {
         Some(it) => it,
         None => return,
     };
@@ -161,12 +157,7 @@ pub(super) fn doc_comment(
     let mut inj = Injector::default();
     inj.add_unmapped("fn doctest() {\n");
 
-    let attrs_source_map = match def {
-        Definition::ModuleDef(hir::ModuleDef::Module(module)) => {
-            attributes.source_map_for_module(sema.db, module.into())
-        }
-        _ => attributes.source_map(node.with_value(&owner)),
-    };
+    let attrs_source_map = attributes.source_map(&owner);
 
     let mut is_codeblock = false;
     let mut is_doctest = false;
@@ -177,10 +168,7 @@ pub(super) fn doc_comment(
     let mut intra_doc_links = Vec::new();
     let mut string;
     for attr in attributes.by_key("doc").attrs() {
-        let InFile { file_id, value: src } = attrs_source_map.source_of(&attr);
-        if file_id != node.file_id {
-            continue;
-        }
+        let src = attrs_source_map.source_of(&attr);
         let (line, range, prefix) = match &src {
             Either::Left(it) => {
                 string = match find_doc_string_in_attr(attr, it) {
@@ -225,16 +213,13 @@ pub(super) fn doc_comment(
                     intra_doc_links.extend(
                         extract_definitions_from_markdown(line)
                             .into_iter()
-                            .filter_map(|(link, ns, range)| {
-                                validate_intra_doc_link(sema.db, &def, &link, ns).zip(Some(range))
+                            .filter(|(link, ns, _)| {
+                                validate_intra_doc_link(sema.db, &def, link, *ns)
                             })
-                            .map(|(def, Range { start, end })| {
-                                (
-                                    def,
-                                    TextRange::at(
-                                        prev_range_start + TextSize::from(start as u32),
-                                        TextSize::from((end - start) as u32),
-                                    ),
+                            .map(|(.., Range { start, end })| {
+                                TextRange::at(
+                                    prev_range_start + TextSize::from(start as u32),
+                                    TextSize::from((end - start) as u32),
                                 )
                             }),
                     );
@@ -258,13 +243,10 @@ pub(super) fn doc_comment(
         }
     }
 
-    for (def, range) in intra_doc_links {
+    for range in intra_doc_links {
         hl.add(HlRange {
             range,
-            highlight: module_def_to_hl_tag(def)
-                | HlMod::Documentation
-                | HlMod::Injected
-                | HlMod::IntraDocLink,
+            highlight: HlTag::IntraDocLink | HlMod::Documentation,
             binding_hash: None,
         });
     }
@@ -295,9 +277,9 @@ pub(super) fn doc_comment(
 }
 
 fn find_doc_string_in_attr(attr: &hir::Attr, it: &ast::Attr) -> Option<ast::String> {
-    match it.literal() {
+    match it.expr() {
         // #[doc = lit]
-        Some(lit) => match lit.kind() {
+        Some(ast::Expr::Literal(lit)) => match lit.kind() {
             ast::LiteralKind::String(it) => Some(it),
             _ => None,
         },
@@ -315,6 +297,7 @@ fn find_doc_string_in_attr(attr: &hir::Attr, it: &ast::Attr) -> Option<ast::Stri
                     string.text().get(1..string.text().len() - 1).map_or(false, |it| it == text)
                 })
         }
+        _ => return None,
     }
 }
 
@@ -323,7 +306,7 @@ fn validate_intra_doc_link(
     def: &Definition,
     link: &str,
     ns: Option<hir::Namespace>,
-) -> Option<hir::ModuleDef> {
+) -> bool {
     match def {
         Definition::ModuleDef(def) => match def {
             hir::ModuleDef::Module(it) => it.resolve_doc_path(db, &link, ns),
@@ -343,21 +326,5 @@ fn validate_intra_doc_link(
         | Definition::GenericParam(_)
         | Definition::Label(_) => None,
     }
-}
-
-fn module_def_to_hl_tag(def: hir::ModuleDef) -> HlTag {
-    let symbol = match def {
-        hir::ModuleDef::Module(_) => SymbolKind::Module,
-        hir::ModuleDef::Function(_) => SymbolKind::Function,
-        hir::ModuleDef::Adt(hir::Adt::Struct(_)) => SymbolKind::Struct,
-        hir::ModuleDef::Adt(hir::Adt::Enum(_)) => SymbolKind::Enum,
-        hir::ModuleDef::Adt(hir::Adt::Union(_)) => SymbolKind::Union,
-        hir::ModuleDef::Variant(_) => SymbolKind::Variant,
-        hir::ModuleDef::Const(_) => SymbolKind::Const,
-        hir::ModuleDef::Static(_) => SymbolKind::Static,
-        hir::ModuleDef::Trait(_) => SymbolKind::Trait,
-        hir::ModuleDef::TypeAlias(_) => SymbolKind::TypeAlias,
-        hir::ModuleDef::BuiltinType(_) => return HlTag::BuiltinType,
-    };
-    HlTag::Symbol(symbol)
+    .is_some()
 }
diff --git a/crates/ide/src/syntax_highlighting/tags.rs b/crates/ide/src/syntax_highlighting/tags.rs
index 93db79b895..ce46e5127a 100644
--- a/crates/ide/src/syntax_highlighting/tags.rs
+++ b/crates/ide/src/syntax_highlighting/tags.rs
@@ -26,6 +26,7 @@ pub enum HlTag {
     Comment,
     EscapeSequence,
     FormatSpecifier,
+    IntraDocLink,
     Keyword,
     NumericLiteral,
     Operator,
@@ -56,8 +57,6 @@ pub enum HlMod {
     Static,
     /// Used for items in impls&traits.
     Associated,
-    /// Used for intra doc links in doc injection.
-    IntraDocLink,
 
     /// Keep this last!
     Unsafe,
@@ -118,6 +117,7 @@ impl HlTag {
             HlTag::Comment => "comment",
             HlTag::EscapeSequence => "escape_sequence",
             HlTag::FormatSpecifier => "format_specifier",
+            HlTag::IntraDocLink => "intra_doc_link",
             HlTag::Keyword => "keyword",
             HlTag::Punctuation(punct) => match punct {
                 HlPunct::Bracket => "bracket",
@@ -151,7 +151,6 @@ impl HlMod {
         HlMod::ControlFlow,
         HlMod::Definition,
         HlMod::Documentation,
-        HlMod::IntraDocLink,
         HlMod::Injected,
         HlMod::Mutable,
         HlMod::Consuming,
@@ -163,18 +162,17 @@ impl HlMod {
 
     fn as_str(self) -> &'static str {
         match self {
-            HlMod::Associated => "associated",
             HlMod::Attribute => "attribute",
-            HlMod::Callable => "callable",
-            HlMod::Consuming => "consuming",
             HlMod::ControlFlow => "control",
             HlMod::Definition => "declaration",
             HlMod::Documentation => "documentation",
             HlMod::Injected => "injected",
-            HlMod::IntraDocLink => "intra_doc_link",
             HlMod::Mutable => "mutable",
-            HlMod::Static => "static",
+            HlMod::Consuming => "consuming",
             HlMod::Unsafe => "unsafe",
+            HlMod::Callable => "callable",
+            HlMod::Static => "static",
+            HlMod::Associated => "associated",
         }
     }
 
diff --git a/crates/ide_assists/src/handlers/qualify_path.rs b/crates/ide_assists/src/handlers/qualify_path.rs
index 40571e52b3..30b23da6ca 100644
--- a/crates/ide_assists/src/handlers/qualify_path.rs
+++ b/crates/ide_assists/src/handlers/qualify_path.rs
@@ -208,10 +208,8 @@ fn label(candidate: &ImportCandidate, import: &LocatedImport) -> String {
                 format!("Qualify as `{}`", import.import_path)
             }
         }
-        ImportCandidate::TraitAssocItem(_) => {
-            format!("Qualify with `{}`", import.import_path)
-        }
-        ImportCandidate::TraitMethod(_) => format!("Qualify with `{}`", import.import_path),
+        ImportCandidate::TraitAssocItem(_) => format!("Qualify `{}`", import.import_path),
+        ImportCandidate::TraitMethod(_) => format!("Qualify with cast as `{}`", import.import_path),
     }
 }
 
@@ -545,37 +543,6 @@ fn main() {
         );
     }
 
-    #[test]
-    fn associated_struct_const_unqualified() {
-        check_assist(
-            qualify_path,
-            r"
-            mod test_mod {
-                pub struct TestStruct {}
-                impl TestStruct {
-                    const TEST_CONST: u8 = 42;
-                }
-            }
-
-            fn main() {
-                TEST_CONST$0
-            }
-            ",
-            r"
-            mod test_mod {
-                pub struct TestStruct {}
-                impl TestStruct {
-                    const TEST_CONST: u8 = 42;
-                }
-            }
-
-            fn main() {
-                test_mod::TestStruct::TEST_CONST
-            }
-            ",
-        );
-    }
-
     #[test]
     fn associated_trait_function() {
         check_assist(
diff --git a/crates/ide_completion/src/render/macro_.rs b/crates/ide_completion/src/render/macro_.rs
index 7578ad50b4..3fa21ba7c9 100644
--- a/crates/ide_completion/src/render/macro_.rs
+++ b/crates/ide_completion/src/render/macro_.rs
@@ -91,7 +91,7 @@ impl<'a> MacroRender<'a> {
     }
 
     fn detail(&self) -> Option<String> {
-        let ast_node = self.macro_.source(self.ctx.db())?.value.left()?;
+        let ast_node = self.macro_.source(self.ctx.db())?.value;
         Some(macro_label(&ast_node))
     }
 }
diff --git a/crates/ide_db/src/helpers/import_assets.rs b/crates/ide_db/src/helpers/import_assets.rs
index 7c8844e959..e03ccd3515 100644
--- a/crates/ide_db/src/helpers/import_assets.rs
+++ b/crates/ide_db/src/helpers/import_assets.rs
@@ -304,11 +304,7 @@ fn path_applicable_imports(
             return items_with_candidate_name
                 .into_iter()
                 .filter_map(|item| {
-                    let mut mod_path = mod_path(item)?;
-                    if let Some(assoc_item) = item_as_assoc(db, item) {
-                        mod_path.push_segment(assoc_item.name(db)?);
-                    }
-                    Some(LocatedImport::new(mod_path.clone(), item, item, Some(mod_path)))
+                    Some(LocatedImport::new(mod_path(item)?, item, item, mod_path(item)))
                 })
                 .collect();
         }
diff --git a/crates/parser/src/grammar/attributes.rs b/crates/parser/src/grammar/attributes.rs
index dab0f62c3c..96791ffc2a 100644
--- a/crates/parser/src/grammar/attributes.rs
+++ b/crates/parser/src/grammar/attributes.rs
@@ -30,8 +30,8 @@ fn attr(p: &mut Parser, inner: bool) {
         match p.current() {
             T![=] => {
                 p.bump(T![=]);
-                if expressions::literal(p).is_none() {
-                    p.error("expected literal");
+                if expressions::expr(p).0.is_none() {
+                    p.error("expected expression");
                 }
             }
             T!['('] | T!['['] | T!['{'] => items::token_tree(p),
diff --git a/crates/rust-analyzer/src/semantic_tokens.rs b/crates/rust-analyzer/src/semantic_tokens.rs
index a3c5e9ccf4..0cb7d12a76 100644
--- a/crates/rust-analyzer/src/semantic_tokens.rs
+++ b/crates/rust-analyzer/src/semantic_tokens.rs
@@ -52,6 +52,7 @@ define_semantic_token_types![
     (ESCAPE_SEQUENCE, "escapeSequence"),
     (FORMAT_SPECIFIER, "formatSpecifier"),
     (GENERIC, "generic"),
+    (INTRA_DOC_LINK, "intraDocLink"),
     (LABEL, "label"),
     (LIFETIME, "lifetime"),
     (PARENTHESIS, "parenthesis"),
@@ -89,7 +90,6 @@ define_semantic_token_modifiers![
     (UNSAFE, "unsafe"),
     (ATTRIBUTE_MODIFIER, "attribute"),
     (CALLABLE, "callable"),
-    (INTRA_DOC_LINK, "intraDocLink"),
 ];
 
 #[derive(Default)]
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index 1ddea92788..70501618e8 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -443,6 +443,7 @@ fn semantic_token_type_and_modifiers(
         HlTag::Comment => lsp_types::SemanticTokenType::COMMENT,
         HlTag::EscapeSequence => semantic_tokens::ESCAPE_SEQUENCE,
         HlTag::FormatSpecifier => semantic_tokens::FORMAT_SPECIFIER,
+        HlTag::IntraDocLink => semantic_tokens::INTRA_DOC_LINK,
         HlTag::Keyword => lsp_types::SemanticTokenType::KEYWORD,
         HlTag::None => semantic_tokens::GENERIC,
         HlTag::Operator => lsp_types::SemanticTokenType::OPERATOR,
@@ -473,7 +474,6 @@ fn semantic_token_type_and_modifiers(
             HlMod::Unsafe => semantic_tokens::UNSAFE,
             HlMod::Callable => semantic_tokens::CALLABLE,
             HlMod::Static => lsp_types::SemanticTokenModifier::STATIC,
-            HlMod::IntraDocLink => semantic_tokens::INTRA_DOC_LINK,
             HlMod::Associated => continue,
         };
         mods |= modifier;
diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs
index 6097178b6f..9a88fdb567 100644
--- a/crates/syntax/src/ast/generated/nodes.rs
+++ b/crates/syntax/src/ast/generated/nodes.rs
@@ -152,7 +152,7 @@ impl Attr {
     pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) }
     pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
     pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
-    pub fn literal(&self) -> Option<Literal> { support::child(&self.syntax) }
+    pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
     pub fn token_tree(&self) -> Option<TokenTree> { support::child(&self.syntax) }
     pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) }
 }
@@ -632,12 +632,6 @@ impl WherePred {
     pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
 }
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct Literal {
-    pub(crate) syntax: SyntaxNode,
-}
-impl ast::AttrsOwner for Literal {}
-impl Literal {}
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct ExprStmt {
     pub(crate) syntax: SyntaxNode,
 }
@@ -805,6 +799,12 @@ impl IndexExpr {
     pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) }
 }
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct Literal {
+    pub(crate) syntax: SyntaxNode,
+}
+impl ast::AttrsOwner for Literal {}
+impl Literal {}
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct LoopExpr {
     pub(crate) syntax: SyntaxNode,
 }
@@ -2072,17 +2072,6 @@ impl AstNode for WherePred {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for Literal {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == LITERAL }
-    fn cast(syntax: SyntaxNode) -> Option<Self> {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
-    }
-    fn syntax(&self) -> &SyntaxNode { &self.syntax }
-}
 impl AstNode for ExprStmt {
     fn can_cast(kind: SyntaxKind) -> bool { kind == EXPR_STMT }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -2259,6 +2248,17 @@ impl AstNode for IndexExpr {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
+impl AstNode for Literal {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == LITERAL }
+    fn cast(syntax: SyntaxNode) -> Option<Self> {
+        if Self::can_cast(syntax.kind()) {
+            Some(Self { syntax })
+        } else {
+            None
+        }
+    }
+    fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
 impl AstNode for LoopExpr {
     fn can_cast(kind: SyntaxKind) -> bool { kind == LOOP_EXPR }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3887,11 +3887,6 @@ impl std::fmt::Display for WherePred {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for Literal {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        std::fmt::Display::fmt(self.syntax(), f)
-    }
-}
 impl std::fmt::Display for ExprStmt {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
@@ -3972,6 +3967,11 @@ impl std::fmt::Display for IndexExpr {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
+impl std::fmt::Display for Literal {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        std::fmt::Display::fmt(self.syntax(), f)
+    }
+}
 impl std::fmt::Display for LoopExpr {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs
index 0b0d39a757..5a9834cbb8 100644
--- a/crates/syntax/src/ast/node_ext.rs
+++ b/crates/syntax/src/ast/node_ext.rs
@@ -109,16 +109,6 @@ impl ast::Attr {
         Some((self.simple_name()?, tt))
     }
 
-    pub fn as_simple_key_value(&self) -> Option<(SmolStr, SmolStr)> {
-        let lit = self.literal()?;
-        let key = self.simple_name()?;
-        let value_token = lit.syntax().first_token()?;
-
-        let value: SmolStr = ast::String::cast(value_token)?.value()?.into();
-
-        Some((key, value))
-    }
-
     pub fn simple_name(&self) -> Option<SmolStr> {
         let path = self.path()?;
         match (path.segment(), path.qualifier()) {
diff --git a/docs/user/manual.adoc b/docs/user/manual.adoc
index dba2197de9..f4c37353cd 100644
--- a/docs/user/manual.adoc
+++ b/docs/user/manual.adoc
@@ -384,9 +384,11 @@ If the LSP binary is not available, GNOME Builder can install it when opening a
 
 === Eclipse IDE
 
+Prerequisites: You have installed the <<rust-analyzer-language-server-binary,`rust-analyzer` binary>>.
+
 Support for Rust development in the Eclipse IDE is provided by link:https://github.com/eclipse/corrosion[Eclipse Corrosion].
-If available in PATH or in some standard location, `rust-analyzer` is detected and powers editing of Rust files without further configuration.
-If `rust-analyzer` is not detected, Corrosion will prompt you for configuration of your Rust toolchain and language server with a link to the __Window > Preferences > Rust__ preference page; from here a button allows to download and configure `rust-analyzer`, but you can also reference another installation.
+While it currently uses RLS as default, you can successfully configure it so the IDE will use `rust-analyzer` instead.
+To do so, with an Eclipse IDE where Corrosion is installed, just go to __Window > Preferences > Rust__ and edit the __Path to Rust Language Server__ entry to reference the path to `rust-analyzer`.
 You'll need to close and reopen all .rs and Cargo files, or to restart the IDE, for this change to take effect.
 
 == Configuration
diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml
index ad93fbe3bd..997770958f 100644
--- a/xtask/Cargo.toml
+++ b/xtask/Cargo.toml
@@ -11,7 +11,7 @@ anyhow = "1.0.26"
 flate2 = "1.0"
 proc-macro2 = "1.0.8"
 quote = "1.0.2"
-ungrammar = "=1.12"
+ungrammar = "=1.13"
 walkdir = "2.3.1"
 write-json = "0.1.0"
 xshell = "0.1"


Test patch:
diff --git a/crates/hir_def/src/nameres/tests/macros.rs b/crates/hir_def/src/nameres/tests/macros.rs
index d59d3c0db1..f65a655bf5 100644
--- a/crates/hir_def/src/nameres/tests/macros.rs
+++ b/crates/hir_def/src/nameres/tests/macros.rs
@@ -1,5 +1,4 @@
 use super::*;
-use crate::nameres::proc_macro::{ProcMacroDef, ProcMacroKind};
 
 #[test]
 fn macro_rules_are_globally_visible() {
@@ -791,28 +790,3 @@ fn proc_macro_censoring() {
         "#]],
     );
 }
-
-#[test]
-fn collects_derive_helpers() {
-    let def_map = compute_crate_def_map(
-        r"
-        struct TokenStream;
-
-        #[proc_macro_derive(AnotherTrait, attributes(helper_attr))]
-        pub fn derive_macro_2(_item: TokenStream) -> TokenStream {
-            TokenStream
-        }
-        ",
-    );
-
-    assert_eq!(def_map.exported_proc_macros.len(), 1);
-    match def_map.exported_proc_macros.values().next() {
-        Some(ProcMacroDef { kind: ProcMacroKind::CustomDerive { helpers }, .. }) => {
-            match &**helpers {
-                [attr] => assert_eq!(attr.to_string(), "helper_attr"),
-                _ => unreachable!(),
-            }
-        }
-        _ => unreachable!(),
-    }
-}
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html b/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html
index 4635ea9276..60c7518af8 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html
@@ -7,7 +7,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .label              { color: #DFAF8F; font-style: italic; }
 .comment            { color: #7F9F7F; }
 .documentation      { color: #629755; }
-.intra_doc_link     { font-style: italic; }
+.intra_doc_link     { color: #A9C577; }
 .injected           { opacity: 0.65 ; }
 .struct, .enum      { color: #7CB8BB; }
 .enum_variant       { color: #BDE0F3; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
index 045162eb83..5d802a6470 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
@@ -7,7 +7,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .label              { color: #DFAF8F; font-style: italic; }
 .comment            { color: #7F9F7F; }
 .documentation      { color: #629755; }
-.intra_doc_link     { font-style: italic; }
+.intra_doc_link     { color: #A9C577; }
 .injected           { opacity: 0.65 ; }
 .struct, .enum      { color: #7CB8BB; }
 .enum_variant       { color: #BDE0F3; }
@@ -99,8 +99,8 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     <span class="brace">}</span>
 <span class="brace">}</span>
 
-<span class="comment documentation">/// </span><span class="struct documentation intra_doc_link injected">[`Foo`](Foo)</span><span class="comment documentation"> is a struct</span>
-<span class="comment documentation">/// </span><span class="function documentation intra_doc_link injected">[`all_the_links`](all_the_links)</span><span class="comment documentation"> is this function</span>
+<span class="comment documentation">/// </span><span class="intra_doc_link documentation">[`Foo`](Foo)</span><span class="comment documentation"> is a struct</span>
+<span class="comment documentation">/// </span><span class="intra_doc_link documentation">[`all_the_links`](all_the_links)</span><span class="comment documentation"> is this function</span>
 <span class="comment documentation">/// [`noop`](noop) is a macro below</span>
 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration">all_the_links</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
 
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html b/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html
index ca9bb1e7d2..4e312765c0 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html
@@ -7,7 +7,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .label              { color: #DFAF8F; font-style: italic; }
 .comment            { color: #7F9F7F; }
 .documentation      { color: #629755; }
-.intra_doc_link     { font-style: italic; }
+.intra_doc_link     { color: #A9C577; }
 .injected           { opacity: 0.65 ; }
 .struct, .enum      { color: #7CB8BB; }
 .enum_variant       { color: #BDE0F3; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
index 9215ddd9e3..57dfe75096 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
@@ -7,7 +7,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .label              { color: #DFAF8F; font-style: italic; }
 .comment            { color: #7F9F7F; }
 .documentation      { color: #629755; }
-.intra_doc_link     { font-style: italic; }
+.intra_doc_link     { color: #A9C577; }
 .injected           { opacity: 0.65 ; }
 .struct, .enum      { color: #7CB8BB; }
 .enum_variant       { color: #BDE0F3; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html b/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
index e860d713e0..75dbd0f142 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
@@ -7,7 +7,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .label              { color: #DFAF8F; font-style: italic; }
 .comment            { color: #7F9F7F; }
 .documentation      { color: #629755; }
-.intra_doc_link     { font-style: italic; }
+.intra_doc_link     { color: #A9C577; }
 .injected           { opacity: 0.65 ; }
 .struct, .enum      { color: #7CB8BB; }
 .enum_variant       { color: #BDE0F3; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
index 6a6555208c..423256a202 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
@@ -7,7 +7,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .label              { color: #DFAF8F; font-style: italic; }
 .comment            { color: #7F9F7F; }
 .documentation      { color: #629755; }
-.intra_doc_link     { font-style: italic; }
+.intra_doc_link     { color: #A9C577; }
 .injected           { opacity: 0.65 ; }
 .struct, .enum      { color: #7CB8BB; }
 .enum_variant       { color: #BDE0F3; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlighting.html b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
index 8b2dd3b70e..fffe8c0f57 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlighting.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
@@ -7,7 +7,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .label              { color: #DFAF8F; font-style: italic; }
 .comment            { color: #7F9F7F; }
 .documentation      { color: #629755; }
-.intra_doc_link     { font-style: italic; }
+.intra_doc_link     { color: #A9C577; }
 .injected           { opacity: 0.65 ; }
 .struct, .enum      { color: #7CB8BB; }
 .enum_variant       { color: #BDE0F3; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/injection.html b/crates/ide/src/syntax_highlighting/test_data/injection.html
index 9ab46d05c0..34d8deb684 100644
--- a/crates/ide/src/syntax_highlighting/test_data/injection.html
+++ b/crates/ide/src/syntax_highlighting/test_data/injection.html
@@ -7,7 +7,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .label              { color: #DFAF8F; font-style: italic; }
 .comment            { color: #7F9F7F; }
 .documentation      { color: #629755; }
-.intra_doc_link     { font-style: italic; }
+.intra_doc_link     { color: #A9C577; }
 .injected           { opacity: 0.65 ; }
 .struct, .enum      { color: #7CB8BB; }
 .enum_variant       { color: #BDE0F3; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/rainbow_highlighting.html b/crates/ide/src/syntax_highlighting/test_data/rainbow_highlighting.html
index 666b0b228d..d9ca3a4c46 100644
--- a/crates/ide/src/syntax_highlighting/test_data/rainbow_highlighting.html
+++ b/crates/ide/src/syntax_highlighting/test_data/rainbow_highlighting.html
@@ -7,7 +7,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .label              { color: #DFAF8F; font-style: italic; }
 .comment            { color: #7F9F7F; }
 .documentation      { color: #629755; }
-.intra_doc_link     { font-style: italic; }
+.intra_doc_link     { color: #A9C577; }
 .injected           { opacity: 0.65 ; }
 .struct, .enum      { color: #7CB8BB; }
 .enum_variant       { color: #BDE0F3; }