about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-01-16 08:39:13 +0000
committerbors <bors@rust-lang.org>2024-01-16 08:39:13 +0000
commit5df53c96127095d75c0724f545ccd280dc0fafa9 (patch)
tree331ab0cda82374456b6b2ff6392b9718f9ba8aea
parent4de8954c4559ed3bc22dd5647db331d4ea0160c7 (diff)
parent180e9b2bbfa39c2c00cfa944d9823cae4867d651 (diff)
downloadrust-5df53c96127095d75c0724f545ccd280dc0fafa9.tar.gz
rust-5df53c96127095d75c0724f545ccd280dc0fafa9.zip
Auto merge of #16351 - Veykril:eager-enum-variant, r=Veykril
internal: Eagerly lower enum variants in CrateDefMap construction
-rw-r--r--crates/hir-def/src/attr.rs95
-rw-r--r--crates/hir-def/src/body.rs7
-rw-r--r--crates/hir-def/src/body/pretty.rs44
-rw-r--r--crates/hir-def/src/child_by_source.rs25
-rw-r--r--crates/hir-def/src/data.rs10
-rw-r--r--crates/hir-def/src/data/adt.rs202
-rw-r--r--crates/hir-def/src/db.rs46
-rw-r--r--crates/hir-def/src/dyn_map/keys.rs2
-rw-r--r--crates/hir-def/src/find_path.rs12
-rw-r--r--crates/hir-def/src/item_tree.rs67
-rw-r--r--crates/hir-def/src/item_tree/lower.rs12
-rw-r--r--crates/hir-def/src/item_tree/pretty.rs2
-rw-r--r--crates/hir-def/src/lang_item.rs8
-rw-r--r--crates/hir-def/src/lib.rs82
-rw-r--r--crates/hir-def/src/nameres.rs8
-rw-r--r--crates/hir-def/src/nameres/collector.rs163
-rw-r--r--crates/hir-def/src/nameres/diagnostics.rs17
-rw-r--r--crates/hir-def/src/nameres/path_resolution.rs51
-rw-r--r--crates/hir-def/src/pretty.rs8
-rw-r--r--crates/hir-def/src/resolver.rs8
-rw-r--r--crates/hir-def/src/src.rs21
-rw-r--r--crates/hir-def/src/trace.rs2
-rw-r--r--crates/hir-def/src/visibility.rs8
-rw-r--r--crates/hir-expand/src/db.rs3
-rw-r--r--crates/hir-ty/src/consteval.rs13
-rw-r--r--crates/hir-ty/src/db.rs2
-rw-r--r--crates/hir-ty/src/diagnostics/decl_check.rs8
-rw-r--r--crates/hir-ty/src/diagnostics/match_check.rs3
-rw-r--r--crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs2
-rw-r--r--crates/hir-ty/src/display.rs16
-rw-r--r--crates/hir-ty/src/infer.rs58
-rw-r--r--crates/hir-ty/src/infer/closure.rs2
-rw-r--r--crates/hir-ty/src/infer/path.rs5
-rw-r--r--crates/hir-ty/src/inhabitedness.rs19
-rw-r--r--crates/hir-ty/src/layout.rs8
-rw-r--r--crates/hir-ty/src/layout/adt.rs17
-rw-r--r--crates/hir-ty/src/lower.rs72
-rw-r--r--crates/hir-ty/src/mir/eval.rs62
-rw-r--r--crates/hir-ty/src/mir/lower.rs16
-rw-r--r--crates/hir-ty/src/mir/lower/pattern_matching.rs24
-rw-r--r--crates/hir-ty/src/mir/pretty.rs15
-rw-r--r--crates/hir-ty/src/tests.rs22
-rw-r--r--crates/hir-ty/src/tls.rs5
-rw-r--r--crates/hir-ty/src/utils.rs26
-rw-r--r--crates/hir/src/attrs.rs2
-rw-r--r--crates/hir/src/db.rs6
-rw-r--r--crates/hir/src/from_id.rs4
-rw-r--r--crates/hir/src/has_source.rs2
-rw-r--r--crates/hir/src/lib.rs48
-rw-r--r--crates/hir/src/semantics/source_to_def.rs2
-rw-r--r--crates/hir/src/symbols.rs4
-rw-r--r--crates/ide-db/src/apply_change.rs5
-rw-r--r--crates/ide-db/src/lib.rs5
-rw-r--r--crates/syntax/src/ast/node_ext.rs6
54 files changed, 673 insertions, 709 deletions
diff --git a/crates/hir-def/src/attr.rs b/crates/hir-def/src/attr.rs
index 30452e34aac..8fbfcc81d28 100644
--- a/crates/hir-def/src/attr.rs
+++ b/crates/hir-def/src/attr.rs
@@ -24,12 +24,12 @@ use triomphe::Arc;
 
 use crate::{
     db::DefDatabase,
-    item_tree::{AttrOwner, Fields, ItemTreeId, ItemTreeNode},
+    item_tree::{AttrOwner, Fields, ItemTreeId, ItemTreeModItemNode},
     lang_item::LangItem,
     nameres::{ModuleOrigin, ModuleSource},
     src::{HasChildSource, HasSource},
-    AdtId, AssocItemLoc, AttrDefId, EnumId, GenericParamId, ItemLoc, LocalEnumVariantId,
-    LocalFieldId, Lookup, MacroId, VariantId,
+    AdtId, AssocItemLoc, AttrDefId, GenericParamId, ItemLoc, LocalFieldId, Lookup, MacroId,
+    VariantId,
 };
 
 #[derive(Default, Debug, Clone, PartialEq, Eq)]
@@ -70,33 +70,6 @@ impl ops::Deref for AttrsWithOwner {
 impl Attrs {
     pub const EMPTY: Self = Self(RawAttrs::EMPTY);
 
-    pub(crate) fn variants_attrs_query(
-        db: &dyn DefDatabase,
-        e: EnumId,
-    ) -> Arc<ArenaMap<LocalEnumVariantId, Attrs>> {
-        let _p = profile::span("variants_attrs_query");
-        // FIXME: There should be some proper form of mapping between item tree enum variant ids and hir enum variant ids
-        let mut res = ArenaMap::default();
-
-        let loc = e.lookup(db);
-        let krate = loc.container.krate;
-        let item_tree = loc.id.item_tree(db);
-        let enum_ = &item_tree[loc.id.value];
-        let crate_graph = db.crate_graph();
-        let cfg_options = &crate_graph[krate].cfg_options;
-
-        let mut idx = 0;
-        for variant in enum_.variants.clone() {
-            let attrs = item_tree.attrs(db, krate, variant.into());
-            if attrs.is_cfg_enabled(cfg_options) {
-                res.insert(Idx::from_raw(RawIdx::from(idx)), attrs);
-                idx += 1;
-            }
-        }
-
-        Arc::new(res)
-    }
-
     pub(crate) fn fields_attrs_query(
         db: &dyn DefDatabase,
         v: VariantId,
@@ -108,29 +81,11 @@ impl Attrs {
         let crate_graph = db.crate_graph();
         let (fields, item_tree, krate) = match v {
             VariantId::EnumVariantId(it) => {
-                let e = it.parent;
-                let loc = e.lookup(db);
-                let krate = loc.container.krate;
+                let loc = it.lookup(db);
+                let krate = loc.parent.lookup(db).container.krate;
                 let item_tree = loc.id.item_tree(db);
-                let enum_ = &item_tree[loc.id.value];
-
-                let cfg_options = &crate_graph[krate].cfg_options;
-
-                let Some(variant) = enum_
-                    .variants
-                    .clone()
-                    .filter(|variant| {
-                        let attrs = item_tree.attrs(db, krate, (*variant).into());
-                        attrs.is_cfg_enabled(cfg_options)
-                    })
-                    .zip(0u32..)
-                    .find(|(_variant, idx)| it.local_id == Idx::from_raw(RawIdx::from(*idx)))
-                    .map(|(variant, _idx)| variant)
-                else {
-                    return Arc::new(res);
-                };
-
-                (item_tree[variant].fields.clone(), item_tree, krate)
+                let variant = &item_tree[loc.id.value];
+                (variant.fields.clone(), item_tree, krate)
             }
             VariantId::StructId(it) => {
                 let loc = it.lookup(db);
@@ -401,10 +356,12 @@ impl AttrsWithOwner {
             AttrDefId::FieldId(it) => {
                 return db.fields_attrs(it.parent)[it.local_id].clone();
             }
+            // FIXME: DRY this up
             AttrDefId::EnumVariantId(it) => {
-                return db.variants_attrs(it.parent)[it.local_id].clone();
+                let id = it.lookup(db).id;
+                let tree = id.item_tree(db);
+                tree.raw_attrs(id.value.into()).clone()
             }
-            // FIXME: DRY this up
             AttrDefId::AdtId(it) => match it {
                 AdtId::StructId(it) => attrs_from_item_tree_loc(db, it),
                 AdtId::EnumId(it) => attrs_from_item_tree_loc(db, it),
@@ -503,12 +460,7 @@ impl AttrsWithOwner {
                 AdtId::EnumId(id) => any_has_attrs(db, id),
             },
             AttrDefId::FunctionId(id) => any_has_attrs(db, id),
-            AttrDefId::EnumVariantId(id) => {
-                let map = db.variants_attrs_source_map(id.parent);
-                let file_id = id.parent.lookup(db).id.file_id();
-                let root = db.parse_or_expand(file_id);
-                InFile::new(file_id, ast::AnyHasAttrs::new(map[id.local_id].to_node(&root)))
-            }
+            AttrDefId::EnumVariantId(id) => any_has_attrs(db, id),
             AttrDefId::StaticId(id) => any_has_attrs(db, id),
             AttrDefId::ConstId(id) => any_has_attrs(db, id),
             AttrDefId::TraitId(id) => any_has_attrs(db, id),
@@ -654,13 +606,16 @@ fn any_has_attrs<'db>(
     id.lookup(db).source(db).map(ast::AnyHasAttrs::new)
 }
 
-fn attrs_from_item_tree<N: ItemTreeNode>(db: &dyn DefDatabase, id: ItemTreeId<N>) -> RawAttrs {
+fn attrs_from_item_tree<N: ItemTreeModItemNode>(
+    db: &dyn DefDatabase,
+    id: ItemTreeId<N>,
+) -> RawAttrs {
     let tree = id.item_tree(db);
     let mod_item = N::id_to_mod_item(id.value);
     tree.raw_attrs(mod_item.into()).clone()
 }
 
-fn attrs_from_item_tree_loc<'db, N: ItemTreeNode>(
+fn attrs_from_item_tree_loc<'db, N: ItemTreeModItemNode>(
     db: &(dyn DefDatabase + 'db),
     lookup: impl Lookup<Database<'db> = dyn DefDatabase + 'db, Data = ItemLoc<N>>,
 ) -> RawAttrs {
@@ -668,7 +623,7 @@ fn attrs_from_item_tree_loc<'db, N: ItemTreeNode>(
     attrs_from_item_tree(db, id)
 }
 
-fn attrs_from_item_tree_assoc<'db, N: ItemTreeNode>(
+fn attrs_from_item_tree_assoc<'db, N: ItemTreeModItemNode>(
     db: &(dyn DefDatabase + 'db),
     lookup: impl Lookup<Database<'db> = dyn DefDatabase + 'db, Data = AssocItemLoc<N>>,
 ) -> RawAttrs {
@@ -676,20 +631,6 @@ fn attrs_from_item_tree_assoc<'db, N: ItemTreeNode>(
     attrs_from_item_tree(db, id)
 }
 
-pub(crate) fn variants_attrs_source_map(
-    db: &dyn DefDatabase,
-    def: EnumId,
-) -> Arc<ArenaMap<LocalEnumVariantId, AstPtr<ast::Variant>>> {
-    let mut res = ArenaMap::default();
-    let child_source = def.child_source(db);
-
-    for (idx, variant) in child_source.value.iter() {
-        res.insert(idx, AstPtr::new(variant));
-    }
-
-    Arc::new(res)
-}
-
 pub(crate) fn fields_attrs_source_map(
     db: &dyn DefDatabase,
     def: VariantId,
diff --git a/crates/hir-def/src/body.rs b/crates/hir-def/src/body.rs
index 415800b9b79..36d810bbe8a 100644
--- a/crates/hir-def/src/body.rs
+++ b/crates/hir-def/src/body.rs
@@ -26,7 +26,7 @@ use crate::{
     },
     nameres::DefMap,
     path::{ModPath, Path},
-    src::{HasChildSource, HasSource},
+    src::HasSource,
     BlockId, DefWithBodyId, HasModule, Lookup,
 };
 
@@ -160,8 +160,9 @@ impl Body {
                     src.map(|it| it.body())
                 }
                 DefWithBodyId::VariantId(v) => {
-                    let src = v.parent.child_source(db);
-                    src.map(|it| it[v.local_id].expr())
+                    let s = v.lookup(db);
+                    let src = s.source(db);
+                    src.map(|it| it.expr())
                 }
                 DefWithBodyId::InTypeConstId(c) => c.lookup(db).id.map(|_| c.source(db).expr()),
             }
diff --git a/crates/hir-def/src/body/pretty.rs b/crates/hir-def/src/body/pretty.rs
index bf887e680f2..0f2b279670c 100644
--- a/crates/hir-def/src/body/pretty.rs
+++ b/crates/hir-def/src/body/pretty.rs
@@ -3,7 +3,6 @@
 use std::fmt::{self, Write};
 
 use itertools::Itertools;
-use syntax::ast::HasName;
 
 use crate::{
     hir::{
@@ -19,35 +18,30 @@ use super::*;
 pub(super) fn print_body_hir(db: &dyn DefDatabase, body: &Body, owner: DefWithBodyId) -> String {
     let header = match owner {
         DefWithBodyId::FunctionId(it) => {
-            let item_tree_id = it.lookup(db).id;
-            format!(
-                "fn {}",
-                item_tree_id.item_tree(db)[item_tree_id.value].name.display(db.upcast())
-            )
+            it.lookup(db).id.resolved(db, |it| format!("fn {}", it.name.display(db.upcast())))
         }
-        DefWithBodyId::StaticId(it) => {
-            let item_tree_id = it.lookup(db).id;
+        DefWithBodyId::StaticId(it) => it
+            .lookup(db)
+            .id
+            .resolved(db, |it| format!("static {} = ", it.name.display(db.upcast()))),
+        DefWithBodyId::ConstId(it) => it.lookup(db).id.resolved(db, |it| {
             format!(
-                "static {} = ",
-                item_tree_id.item_tree(db)[item_tree_id.value].name.display(db.upcast())
+                "const {} = ",
+                match &it.name {
+                    Some(name) => name.display(db.upcast()).to_string(),
+                    None => "_".to_string(),
+                }
             )
-        }
-        DefWithBodyId::ConstId(it) => {
-            let item_tree_id = it.lookup(db).id;
-            let name = match &item_tree_id.item_tree(db)[item_tree_id.value].name {
-                Some(name) => name.display(db.upcast()).to_string(),
-                None => "_".to_string(),
-            };
-            format!("const {name} = ")
-        }
+        }),
         DefWithBodyId::InTypeConstId(_) => format!("In type const = "),
         DefWithBodyId::VariantId(it) => {
-            let src = it.parent.child_source(db);
-            let variant = &src.value[it.local_id];
-            match &variant.name() {
-                Some(name) => name.to_string(),
-                None => "_".to_string(),
-            }
+            let loc = it.lookup(db);
+            let enum_loc = loc.parent.lookup(db);
+            format!(
+                "enum {}::{}",
+                enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db.upcast()),
+                loc.id.item_tree(db)[loc.id.value].name.display(db.upcast()),
+            )
         }
     };
 
diff --git a/crates/hir-def/src/child_by_source.rs b/crates/hir-def/src/child_by_source.rs
index 32c53cb9503..b3bb3355f12 100644
--- a/crates/hir-def/src/child_by_source.rs
+++ b/crates/hir-def/src/child_by_source.rs
@@ -13,8 +13,8 @@ use crate::{
     item_scope::ItemScope,
     nameres::DefMap,
     src::{HasChildSource, HasSource},
-    AdtId, AssocItemId, DefWithBodyId, EnumId, EnumVariantId, ExternCrateId, FieldId, ImplId,
-    Lookup, MacroId, ModuleDefId, ModuleId, TraitId, UseId, VariantId,
+    AdtId, AssocItemId, DefWithBodyId, EnumId, ExternCrateId, FieldId, ImplId, Lookup, MacroId,
+    ModuleDefId, ModuleId, TraitId, UseId, VariantId,
 };
 
 pub trait ChildBySource {
@@ -204,13 +204,22 @@ impl ChildBySource for VariantId {
 }
 
 impl ChildBySource for EnumId {
-    fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, _: HirFileId) {
-        let arena_map = self.child_source(db);
-        let arena_map = arena_map.as_ref();
-        for (local_id, source) in arena_map.value.iter() {
-            let id = EnumVariantId { parent: *self, local_id };
-            res[keys::VARIANT].insert(source.clone(), id)
+    fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) {
+        let loc = &self.lookup(db);
+        if file_id != loc.id.file_id() {
+            return;
         }
+
+        let tree = loc.id.item_tree(db);
+        let ast_id_map = db.ast_id_map(loc.id.file_id());
+        let root = db.parse_or_expand(loc.id.file_id());
+
+        db.enum_data(*self).variants.iter().for_each(|&(variant, _)| {
+            res[keys::ENUM_VARIANT].insert(
+                ast_id_map.get(tree[variant.lookup(db).id.value].ast_id).to_node(&root),
+                variant,
+            );
+        });
     }
 }
 
diff --git a/crates/hir-def/src/data.rs b/crates/hir-def/src/data.rs
index 9c183c9332b..a42d6bb3378 100644
--- a/crates/hir-def/src/data.rs
+++ b/crates/hir-def/src/data.rs
@@ -19,7 +19,7 @@ use crate::{
     macro_call_as_call_id,
     nameres::{
         attr_resolution::ResolvedAttr,
-        diagnostics::DefDiagnostic,
+        diagnostics::{DefDiagnostic, DefDiagnostics},
         proc_macro::{parse_macro_name_and_helper_attrs, ProcMacroKind},
         DefMap, MacroSubNs,
     },
@@ -240,7 +240,7 @@ impl TraitData {
     pub(crate) fn trait_data_with_diagnostics_query(
         db: &dyn DefDatabase,
         tr: TraitId,
-    ) -> (Arc<TraitData>, Arc<[DefDiagnostic]>) {
+    ) -> (Arc<TraitData>, DefDiagnostics) {
         let tr_loc @ ItemLoc { container: module_id, id: tree_id } = tr.lookup(db);
         let item_tree = tree_id.item_tree(db);
         let tr_def = &item_tree[tree_id.value];
@@ -274,7 +274,7 @@ impl TraitData {
                 rustc_has_incoherent_inherent_impls,
                 fundamental,
             }),
-            diagnostics.into(),
+            DefDiagnostics::new(diagnostics),
         )
     }
 
@@ -340,7 +340,7 @@ impl ImplData {
     pub(crate) fn impl_data_with_diagnostics_query(
         db: &dyn DefDatabase,
         id: ImplId,
-    ) -> (Arc<ImplData>, Arc<[DefDiagnostic]>) {
+    ) -> (Arc<ImplData>, DefDiagnostics) {
         let _p = profile::span("impl_data_with_diagnostics_query");
         let ItemLoc { container: module_id, id: tree_id } = id.lookup(db);
 
@@ -367,7 +367,7 @@ impl ImplData {
                 is_unsafe,
                 attribute_calls,
             }),
-            diagnostics.into(),
+            DefDiagnostics::new(diagnostics),
         )
     }
 
diff --git a/crates/hir-def/src/data/adt.rs b/crates/hir-def/src/data/adt.rs
index 8772c34f02f..5d443715213 100644
--- a/crates/hir-def/src/data/adt.rs
+++ b/crates/hir-def/src/data/adt.rs
@@ -21,15 +21,14 @@ use crate::{
     item_tree::{AttrOwner, Field, FieldAstId, Fields, ItemTree, ModItem, RawVisibilityId},
     lang_item::LangItem,
     lower::LowerCtx,
-    nameres::diagnostics::DefDiagnostic,
+    nameres::diagnostics::{DefDiagnostic, DefDiagnostics},
     src::HasChildSource,
     src::HasSource,
     trace::Trace,
     tt::{Delimiter, DelimiterKind, Leaf, Subtree, TokenTree},
     type_ref::TypeRef,
     visibility::RawVisibility,
-    EnumId, EnumLoc, LocalEnumVariantId, LocalFieldId, LocalModuleId, Lookup, ModuleId, StructId,
-    UnionId, VariantId,
+    EnumId, EnumVariantId, LocalFieldId, LocalModuleId, Lookup, StructId, UnionId, VariantId,
 };
 
 /// Note that we use `StructData` for unions as well!
@@ -43,7 +42,7 @@ pub struct StructData {
 }
 
 bitflags! {
-#[derive(Debug, Clone, PartialEq, Eq)]
+    #[derive(Debug, Clone, PartialEq, Eq)]
     pub struct StructFlags: u8 {
         const NO_FLAGS         = 0;
         /// Indicates whether the struct is `PhantomData`.
@@ -65,7 +64,7 @@ bitflags! {
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub struct EnumData {
     pub name: Name,
-    pub variants: Arena<EnumVariantData>,
+    pub variants: Box<[(EnumVariantId, Name)]>,
     pub repr: Option<ReprOptions>,
     pub visibility: RawVisibility,
     pub rustc_has_incoherent_inherent_impls: bool,
@@ -75,7 +74,6 @@ pub struct EnumData {
 pub struct EnumVariantData {
     pub name: Name,
     pub variant_data: Arc<VariantData>,
-    pub tree_id: la_arena::Idx<crate::item_tree::Variant>,
 }
 
 #[derive(Debug, Clone, PartialEq, Eq)]
@@ -189,7 +187,7 @@ impl StructData {
     pub(crate) fn struct_data_with_diagnostics_query(
         db: &dyn DefDatabase,
         id: StructId,
-    ) -> (Arc<StructData>, Arc<[DefDiagnostic]>) {
+    ) -> (Arc<StructData>, DefDiagnostics) {
         let loc = id.lookup(db);
         let krate = loc.container.krate;
         let item_tree = loc.id.item_tree(db);
@@ -234,7 +232,7 @@ impl StructData {
                 visibility: item_tree[strukt.visibility].clone(),
                 flags,
             }),
-            diagnostics.into(),
+            DefDiagnostics::new(diagnostics),
         )
     }
 
@@ -245,7 +243,7 @@ impl StructData {
     pub(crate) fn union_data_with_diagnostics_query(
         db: &dyn DefDatabase,
         id: UnionId,
-    ) -> (Arc<StructData>, Arc<[DefDiagnostic]>) {
+    ) -> (Arc<StructData>, DefDiagnostics) {
         let loc = id.lookup(db);
         let krate = loc.container.krate;
         let item_tree = loc.id.item_tree(db);
@@ -280,24 +278,16 @@ impl StructData {
                 visibility: item_tree[union.visibility].clone(),
                 flags,
             }),
-            diagnostics.into(),
+            DefDiagnostics::new(diagnostics),
         )
     }
 }
 
 impl EnumData {
     pub(crate) fn enum_data_query(db: &dyn DefDatabase, e: EnumId) -> Arc<EnumData> {
-        db.enum_data_with_diagnostics(e).0
-    }
-
-    pub(crate) fn enum_data_with_diagnostics_query(
-        db: &dyn DefDatabase,
-        e: EnumId,
-    ) -> (Arc<EnumData>, Arc<[DefDiagnostic]>) {
         let loc = e.lookup(db);
         let krate = loc.container.krate;
         let item_tree = loc.id.item_tree(db);
-        let cfg_options = db.crate_graph()[krate].cfg_options.clone();
         let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into());
         let rustc_has_incoherent_inherent_impls = item_tree
             .attrs(db, loc.container.krate, ModItem::from(loc.id.value).into())
@@ -305,53 +295,21 @@ impl EnumData {
             .exists();
 
         let enum_ = &item_tree[loc.id.value];
-        let mut variants = Arena::new();
-        let mut diagnostics = Vec::new();
-        for tree_id in enum_.variants.clone() {
-            let attrs = item_tree.attrs(db, krate, tree_id.into());
-            let var = &item_tree[tree_id];
-            if attrs.is_cfg_enabled(&cfg_options) {
-                let (var_data, field_diagnostics) = lower_fields(
-                    db,
-                    krate,
-                    loc.id.file_id(),
-                    loc.container.local_id,
-                    &item_tree,
-                    &cfg_options,
-                    &var.fields,
-                    Some(enum_.visibility),
-                );
-                diagnostics.extend(field_diagnostics);
-
-                variants.alloc(EnumVariantData {
-                    name: var.name.clone(),
-                    variant_data: Arc::new(var_data),
-                    tree_id,
-                });
-            } else {
-                diagnostics.push(DefDiagnostic::unconfigured_code(
-                    loc.container.local_id,
-                    InFile::new(loc.id.file_id(), var.ast_id.erase()),
-                    attrs.cfg().unwrap(),
-                    cfg_options.clone(),
-                ))
-            }
-        }
 
-        (
-            Arc::new(EnumData {
-                name: enum_.name.clone(),
-                variants,
-                repr,
-                visibility: item_tree[enum_.visibility].clone(),
-                rustc_has_incoherent_inherent_impls,
-            }),
-            diagnostics.into(),
-        )
+        Arc::new(EnumData {
+            name: enum_.name.clone(),
+            variants: loc.container.def_map(db).enum_definitions[&e]
+                .iter()
+                .map(|&id| (id, item_tree[id.lookup(db).id.value].name.clone()))
+                .collect(),
+            repr,
+            visibility: item_tree[enum_.visibility].clone(),
+            rustc_has_incoherent_inherent_impls,
+        })
     }
 
-    pub fn variant(&self, name: &Name) -> Option<LocalEnumVariantId> {
-        let (id, _) = self.variants.iter().find(|(_id, data)| &data.name == name)?;
+    pub fn variant(&self, name: &Name) -> Option<EnumVariantId> {
+        let &(id, _) = self.variants.iter().find(|(_id, n)| n == name)?;
         Some(id)
     }
 
@@ -363,82 +321,47 @@ impl EnumData {
     }
 }
 
-impl HasChildSource<LocalEnumVariantId> for EnumId {
-    type Value = ast::Variant;
-    fn child_source(
-        &self,
+impl EnumVariantData {
+    pub(crate) fn enum_variant_data_query(
         db: &dyn DefDatabase,
-    ) -> InFile<ArenaMap<LocalEnumVariantId, Self::Value>> {
-        let loc = &self.lookup(db);
-        let src = loc.source(db);
-        let mut trace = Trace::new_for_map();
-        lower_enum(db, &mut trace, &src, loc);
-        src.with_value(trace.into_map())
+        e: EnumVariantId,
+    ) -> Arc<EnumVariantData> {
+        db.enum_variant_data_with_diagnostics(e).0
     }
-}
 
-fn lower_enum(
-    db: &dyn DefDatabase,
-    trace: &mut Trace<EnumVariantData, ast::Variant>,
-    ast: &InFile<ast::Enum>,
-    loc: &EnumLoc,
-) {
-    let item_tree = loc.id.item_tree(db);
-    let krate = loc.container.krate;
-
-    let item_tree_variants = item_tree[loc.id.value].variants.clone();
-
-    let cfg_options = &db.crate_graph()[krate].cfg_options;
-    let variants = ast
-        .value
-        .variant_list()
-        .into_iter()
-        .flat_map(|it| it.variants())
-        .zip(item_tree_variants)
-        .filter(|&(_, item_tree_id)| {
-            item_tree.attrs(db, krate, item_tree_id.into()).is_cfg_enabled(cfg_options)
-        });
-    for (var, item_tree_id) in variants {
-        trace.alloc(
-            || var.clone(),
-            || EnumVariantData {
-                name: var.name().map_or_else(Name::missing, |it| it.as_name()),
-                variant_data: Arc::new(VariantData::new(
-                    db,
-                    ast.with_value(var.kind()),
-                    loc.container,
-                    &item_tree,
-                    item_tree_id,
-                )),
-                tree_id: item_tree_id,
-            },
+    pub(crate) fn enum_variant_data_with_diagnostics_query(
+        db: &dyn DefDatabase,
+        e: EnumVariantId,
+    ) -> (Arc<EnumVariantData>, DefDiagnostics) {
+        let loc = e.lookup(db);
+        let container = loc.parent.lookup(db).container;
+        let krate = container.krate;
+        let item_tree = loc.id.item_tree(db);
+        let cfg_options = db.crate_graph()[krate].cfg_options.clone();
+        let variant = &item_tree[loc.id.value];
+
+        let (var_data, diagnostics) = lower_fields(
+            db,
+            krate,
+            loc.id.file_id(),
+            container.local_id,
+            &item_tree,
+            &cfg_options,
+            &variant.fields,
+            Some(item_tree[loc.parent.lookup(db).id.value].visibility),
         );
+
+        (
+            Arc::new(EnumVariantData {
+                name: variant.name.clone(),
+                variant_data: Arc::new(var_data),
+            }),
+            DefDiagnostics::new(diagnostics),
+        )
     }
 }
 
 impl VariantData {
-    fn new(
-        db: &dyn DefDatabase,
-        flavor: InFile<ast::StructKind>,
-        module_id: ModuleId,
-        item_tree: &ItemTree,
-        variant: la_arena::Idx<crate::item_tree::Variant>,
-    ) -> Self {
-        let mut trace = Trace::new_for_arena();
-        match lower_struct(
-            db,
-            &mut trace,
-            &flavor,
-            module_id.krate,
-            item_tree,
-            &item_tree[variant].fields,
-        ) {
-            StructKind::Tuple => VariantData::Tuple(trace.into_arena()),
-            StructKind::Record => VariantData::Record(trace.into_arena()),
-            StructKind::Unit => VariantData::Unit,
-        }
-    }
-
     pub fn fields(&self) -> &Arena<FieldData> {
         const EMPTY: &Arena<FieldData> = &Arena::new();
         match &self {
@@ -468,14 +391,13 @@ impl HasChildSource<LocalFieldId> for VariantId {
         let item_tree;
         let (src, fields, container) = match *self {
             VariantId::EnumVariantId(it) => {
-                // I don't really like the fact that we call into parent source
-                // here, this might add to more queries then necessary.
-                let lookup = it.parent.lookup(db);
+                let lookup = it.lookup(db);
                 item_tree = lookup.id.item_tree(db);
-                let src = it.parent.child_source(db);
-                let tree_id = db.enum_data(it.parent).variants[it.local_id].tree_id;
-                let fields = &item_tree[tree_id].fields;
-                (src.map(|map| map[it.local_id].kind()), fields, lookup.container)
+                (
+                    lookup.source(db).map(|it| it.kind()),
+                    &item_tree[lookup.id.value].fields,
+                    lookup.parent.lookup(db).container,
+                )
             }
             VariantId::StructId(it) => {
                 let lookup = it.lookup(db);
@@ -490,11 +412,7 @@ impl HasChildSource<LocalFieldId> for VariantId {
                 let lookup = it.lookup(db);
                 item_tree = lookup.id.item_tree(db);
                 (
-                    lookup.source(db).map(|it| {
-                        it.record_field_list()
-                            .map(ast::StructKind::Record)
-                            .unwrap_or(ast::StructKind::Unit)
-                    }),
+                    lookup.source(db).map(|it| it.kind()),
                     &item_tree[lookup.id.value].fields,
                     lookup.container,
                 )
diff --git a/crates/hir-def/src/db.rs b/crates/hir-def/src/db.rs
index 70c0d5193d4..186a8cf2d9f 100644
--- a/crates/hir-def/src/db.rs
+++ b/crates/hir-def/src/db.rs
@@ -11,7 +11,7 @@ use crate::{
     attr::{Attrs, AttrsWithOwner},
     body::{scope::ExprScopes, Body, BodySourceMap},
     data::{
-        adt::{EnumData, StructData},
+        adt::{EnumData, EnumVariantData, StructData},
         ConstData, ExternCrateDeclData, FunctionData, ImplData, Macro2Data, MacroRulesData,
         ProcMacroData, StaticData, TraitAliasData, TraitData, TypeAliasData,
     },
@@ -19,15 +19,15 @@ use crate::{
     import_map::ImportMap,
     item_tree::{AttrOwner, ItemTree},
     lang_item::{self, LangItem, LangItemTarget, LangItems},
-    nameres::{diagnostics::DefDiagnostic, DefMap},
+    nameres::{diagnostics::DefDiagnostics, DefMap},
     visibility::{self, Visibility},
     AttrDefId, BlockId, BlockLoc, ConstBlockId, ConstBlockLoc, ConstId, ConstLoc, DefWithBodyId,
-    EnumId, EnumLoc, ExternBlockId, ExternBlockLoc, ExternCrateId, ExternCrateLoc, FunctionId,
-    FunctionLoc, GenericDefId, ImplId, ImplLoc, InTypeConstId, InTypeConstLoc, LocalEnumVariantId,
-    LocalFieldId, Macro2Id, Macro2Loc, MacroId, MacroRulesId, MacroRulesLoc, MacroRulesLocFlags,
-    ProcMacroId, ProcMacroLoc, StaticId, StaticLoc, StructId, StructLoc, TraitAliasId,
-    TraitAliasLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, UseId, UseLoc,
-    VariantId,
+    EnumId, EnumLoc, EnumVariantId, EnumVariantLoc, ExternBlockId, ExternBlockLoc, ExternCrateId,
+    ExternCrateLoc, FunctionId, FunctionLoc, GenericDefId, ImplId, ImplLoc, InTypeConstId,
+    InTypeConstLoc, LocalFieldId, Macro2Id, Macro2Loc, MacroId, MacroRulesId, MacroRulesLoc,
+    MacroRulesLocFlags, ProcMacroId, ProcMacroLoc, StaticId, StaticLoc, StructId, StructLoc,
+    TraitAliasId, TraitAliasLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc,
+    UseId, UseLoc, VariantId,
 };
 
 #[salsa::query_group(InternDatabaseStorage)]
@@ -46,6 +46,8 @@ pub trait InternDatabase: SourceDatabase {
     #[salsa::interned]
     fn intern_enum(&self, loc: EnumLoc) -> EnumId;
     #[salsa::interned]
+    fn intern_enum_variant(&self, loc: EnumVariantLoc) -> EnumVariantId;
+    #[salsa::interned]
     fn intern_const(&self, loc: ConstLoc) -> ConstId;
     #[salsa::interned]
     fn intern_static(&self, loc: StaticLoc) -> StaticId;
@@ -119,32 +121,37 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDataba
     fn struct_data(&self, id: StructId) -> Arc<StructData>;
 
     #[salsa::invoke(StructData::struct_data_with_diagnostics_query)]
-    fn struct_data_with_diagnostics(&self, id: StructId)
-        -> (Arc<StructData>, Arc<[DefDiagnostic]>);
+    fn struct_data_with_diagnostics(&self, id: StructId) -> (Arc<StructData>, DefDiagnostics);
 
     #[salsa::invoke(StructData::union_data_query)]
     fn union_data(&self, id: UnionId) -> Arc<StructData>;
 
     #[salsa::invoke(StructData::union_data_with_diagnostics_query)]
-    fn union_data_with_diagnostics(&self, id: UnionId) -> (Arc<StructData>, Arc<[DefDiagnostic]>);
+    fn union_data_with_diagnostics(&self, id: UnionId) -> (Arc<StructData>, DefDiagnostics);
 
     #[salsa::invoke(EnumData::enum_data_query)]
     fn enum_data(&self, e: EnumId) -> Arc<EnumData>;
 
-    #[salsa::invoke(EnumData::enum_data_with_diagnostics_query)]
-    fn enum_data_with_diagnostics(&self, e: EnumId) -> (Arc<EnumData>, Arc<[DefDiagnostic]>);
+    #[salsa::invoke(EnumVariantData::enum_variant_data_query)]
+    fn enum_variant_data(&self, id: EnumVariantId) -> Arc<EnumVariantData>;
+
+    #[salsa::invoke(EnumVariantData::enum_variant_data_with_diagnostics_query)]
+    fn enum_variant_data_with_diagnostics(
+        &self,
+        id: EnumVariantId,
+    ) -> (Arc<EnumVariantData>, DefDiagnostics);
 
     #[salsa::invoke(ImplData::impl_data_query)]
     fn impl_data(&self, e: ImplId) -> Arc<ImplData>;
 
     #[salsa::invoke(ImplData::impl_data_with_diagnostics_query)]
-    fn impl_data_with_diagnostics(&self, e: ImplId) -> (Arc<ImplData>, Arc<[DefDiagnostic]>);
+    fn impl_data_with_diagnostics(&self, e: ImplId) -> (Arc<ImplData>, DefDiagnostics);
 
     #[salsa::invoke(TraitData::trait_data_query)]
     fn trait_data(&self, e: TraitId) -> Arc<TraitData>;
 
     #[salsa::invoke(TraitData::trait_data_with_diagnostics_query)]
-    fn trait_data_with_diagnostics(&self, tr: TraitId) -> (Arc<TraitData>, Arc<[DefDiagnostic]>);
+    fn trait_data_with_diagnostics(&self, tr: TraitId) -> (Arc<TraitData>, DefDiagnostics);
 
     #[salsa::invoke(TraitAliasData::trait_alias_query)]
     fn trait_alias_data(&self, e: TraitAliasId) -> Arc<TraitAliasData>;
@@ -189,18 +196,9 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDataba
 
     // region:attrs
 
-    #[salsa::invoke(Attrs::variants_attrs_query)]
-    fn variants_attrs(&self, def: EnumId) -> Arc<ArenaMap<LocalEnumVariantId, Attrs>>;
-
     #[salsa::invoke(Attrs::fields_attrs_query)]
     fn fields_attrs(&self, def: VariantId) -> Arc<ArenaMap<LocalFieldId, Attrs>>;
 
-    #[salsa::invoke(crate::attr::variants_attrs_source_map)]
-    fn variants_attrs_source_map(
-        &self,
-        def: EnumId,
-    ) -> Arc<ArenaMap<LocalEnumVariantId, AstPtr<ast::Variant>>>;
-
     #[salsa::invoke(crate::attr::fields_attrs_source_map)]
     fn fields_attrs_source_map(
         &self,
diff --git a/crates/hir-def/src/dyn_map/keys.rs b/crates/hir-def/src/dyn_map/keys.rs
index d0f2bfab432..60832f59eb9 100644
--- a/crates/hir-def/src/dyn_map/keys.rs
+++ b/crates/hir-def/src/dyn_map/keys.rs
@@ -28,7 +28,7 @@ pub const ENUM: Key<ast::Enum, EnumId> = Key::new();
 pub const EXTERN_CRATE: Key<ast::ExternCrate, ExternCrateId> = Key::new();
 pub const USE: Key<ast::Use, UseId> = Key::new();
 
-pub const VARIANT: Key<ast::Variant, EnumVariantId> = Key::new();
+pub const ENUM_VARIANT: Key<ast::Variant, EnumVariantId> = Key::new();
 pub const TUPLE_FIELD: Key<ast::TupleField, FieldId> = Key::new();
 pub const RECORD_FIELD: Key<ast::RecordField, FieldId> = Key::new();
 pub const TYPE_PARAM: Key<ast::TypeParam, TypeOrConstParamId> = Key::new();
diff --git a/crates/hir-def/src/find_path.rs b/crates/hir-def/src/find_path.rs
index 67e43f15cd3..3ff51b9845c 100644
--- a/crates/hir-def/src/find_path.rs
+++ b/crates/hir-def/src/find_path.rs
@@ -2,7 +2,10 @@
 
 use std::{cmp::Ordering, iter};
 
-use hir_expand::name::{known, AsName, Name};
+use hir_expand::{
+    name::{known, AsName, Name},
+    Lookup,
+};
 use rustc_hash::FxHashSet;
 
 use crate::{
@@ -139,9 +142,10 @@ fn find_path_inner(ctx: FindPathCtx<'_>, item: ItemInNs, from: ModuleId) -> Opti
 
     if let Some(ModuleDefId::EnumVariantId(variant)) = item.as_module_def_id() {
         // - if the item is an enum variant, refer to it via the enum
-        if let Some(mut path) = find_path_inner(ctx, ItemInNs::Types(variant.parent.into()), from) {
-            let data = ctx.db.enum_data(variant.parent);
-            path.push_segment(data.variants[variant.local_id].name.clone());
+        if let Some(mut path) =
+            find_path_inner(ctx, ItemInNs::Types(variant.lookup(ctx.db).parent.into()), from)
+        {
+            path.push_segment(ctx.db.enum_variant_data(variant).name.clone());
             return Some(path);
         }
         // If this doesn't work, it seems we have no way of referring to the
diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs
index 82ea5ffeba1..c37cf521551 100644
--- a/crates/hir-def/src/item_tree.rs
+++ b/crates/hir-def/src/item_tree.rs
@@ -41,7 +41,7 @@ mod tests;
 use std::{
     fmt::{self, Debug},
     hash::{Hash, Hasher},
-    ops::Index,
+    ops::{Index, Range},
 };
 
 use ast::{AstNode, HasName, StructKind};
@@ -308,7 +308,7 @@ pub enum AttrOwner {
     /// Inner attributes of the source file.
     TopLevel,
 
-    Variant(Idx<Variant>),
+    Variant(FileItemTreeId<Variant>),
     Field(Idx<Field>),
     Param(Idx<Param>),
     TypeOrConstParamData(Idx<TypeOrConstParamData>),
@@ -329,7 +329,7 @@ macro_rules! from_attrs {
 
 from_attrs!(
     ModItem(ModItem),
-    Variant(Idx<Variant>),
+    Variant(FileItemTreeId<Variant>),
     Field(Idx<Field>),
     Param(Idx<Param>),
     TypeOrConstParamData(Idx<TypeOrConstParamData>),
@@ -337,7 +337,7 @@ from_attrs!(
 );
 
 /// Trait implemented by all item nodes in the item tree.
-pub trait ItemTreeNode: Clone {
+pub trait ItemTreeModItemNode: Clone {
     type Source: AstIdNode + Into<ast::Item>;
 
     fn ast_id(&self) -> FileAstId<Self::Source>;
@@ -352,35 +352,44 @@ pub trait ItemTreeNode: Clone {
     fn id_to_mod_item(id: FileItemTreeId<Self>) -> ModItem;
 }
 
-pub struct FileItemTreeId<N: ItemTreeNode>(Idx<N>);
+pub struct FileItemTreeId<N>(Idx<N>);
 
-impl<N: ItemTreeNode> FileItemTreeId<N> {
+impl<N> FileItemTreeId<N> {
+    pub fn range_iter(range: Range<Self>) -> impl Iterator<Item = Self> {
+        (range.start.index().into_raw().into_u32()..range.end.index().into_raw().into_u32())
+            .map(RawIdx::from_u32)
+            .map(Idx::from_raw)
+            .map(Self)
+    }
+}
+
+impl<N> FileItemTreeId<N> {
     pub fn index(&self) -> Idx<N> {
         self.0
     }
 }
 
-impl<N: ItemTreeNode> Clone for FileItemTreeId<N> {
+impl<N> Clone for FileItemTreeId<N> {
     fn clone(&self) -> Self {
         Self(self.0)
     }
 }
-impl<N: ItemTreeNode> Copy for FileItemTreeId<N> {}
+impl<N> Copy for FileItemTreeId<N> {}
 
-impl<N: ItemTreeNode> PartialEq for FileItemTreeId<N> {
+impl<N> PartialEq for FileItemTreeId<N> {
     fn eq(&self, other: &FileItemTreeId<N>) -> bool {
         self.0 == other.0
     }
 }
-impl<N: ItemTreeNode> Eq for FileItemTreeId<N> {}
+impl<N> Eq for FileItemTreeId<N> {}
 
-impl<N: ItemTreeNode> Hash for FileItemTreeId<N> {
+impl<N> Hash for FileItemTreeId<N> {
     fn hash<H: Hasher>(&self, state: &mut H) {
         self.0.hash(state)
     }
 }
 
-impl<N: ItemTreeNode> fmt::Debug for FileItemTreeId<N> {
+impl<N> fmt::Debug for FileItemTreeId<N> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         self.0.fmt(f)
     }
@@ -415,12 +424,12 @@ impl TreeId {
 }
 
 #[derive(Debug)]
-pub struct ItemTreeId<N: ItemTreeNode> {
+pub struct ItemTreeId<N> {
     tree: TreeId,
     pub value: FileItemTreeId<N>,
 }
 
-impl<N: ItemTreeNode> ItemTreeId<N> {
+impl<N> ItemTreeId<N> {
     pub fn new(tree: TreeId, idx: FileItemTreeId<N>) -> Self {
         Self { tree, value: idx }
     }
@@ -436,24 +445,31 @@ impl<N: ItemTreeNode> ItemTreeId<N> {
     pub fn item_tree(self, db: &dyn DefDatabase) -> Arc<ItemTree> {
         self.tree.item_tree(db)
     }
+
+    pub fn resolved<R>(self, db: &dyn DefDatabase, cb: impl FnOnce(&N) -> R) -> R
+    where
+        ItemTree: Index<FileItemTreeId<N>, Output = N>,
+    {
+        cb(&self.tree.item_tree(db)[self.value])
+    }
 }
 
-impl<N: ItemTreeNode> Copy for ItemTreeId<N> {}
-impl<N: ItemTreeNode> Clone for ItemTreeId<N> {
+impl<N> Copy for ItemTreeId<N> {}
+impl<N> Clone for ItemTreeId<N> {
     fn clone(&self) -> Self {
         *self
     }
 }
 
-impl<N: ItemTreeNode> PartialEq for ItemTreeId<N> {
+impl<N> PartialEq for ItemTreeId<N> {
     fn eq(&self, other: &Self) -> bool {
         self.tree == other.tree && self.value == other.value
     }
 }
 
-impl<N: ItemTreeNode> Eq for ItemTreeId<N> {}
+impl<N> Eq for ItemTreeId<N> {}
 
-impl<N: ItemTreeNode> Hash for ItemTreeId<N> {
+impl<N> Hash for ItemTreeId<N> {
     fn hash<H: Hasher>(&self, state: &mut H) {
         self.tree.hash(state);
         self.value.hash(state);
@@ -478,7 +494,7 @@ macro_rules! mod_items {
         )+
 
         $(
-            impl ItemTreeNode for $typ {
+            impl ItemTreeModItemNode for $typ {
                 type Source = $ast;
 
                 fn ast_id(&self) -> FileAstId<Self::Source> {
@@ -561,13 +577,20 @@ impl Index<RawVisibilityId> for ItemTree {
     }
 }
 
-impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree {
+impl<N: ItemTreeModItemNode> Index<FileItemTreeId<N>> for ItemTree {
     type Output = N;
     fn index(&self, id: FileItemTreeId<N>) -> &N {
         N::lookup(self, id.index())
     }
 }
 
+impl Index<FileItemTreeId<Variant>> for ItemTree {
+    type Output = Variant;
+    fn index(&self, id: FileItemTreeId<Variant>) -> &Variant {
+        &self[id.index()]
+    }
+}
+
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub struct Use {
     pub visibility: RawVisibilityId,
@@ -678,7 +701,7 @@ pub struct Enum {
     pub name: Name,
     pub visibility: RawVisibilityId,
     pub generic_params: Interned<GenericParams>,
-    pub variants: IdxRange<Variant>,
+    pub variants: Range<FileItemTreeId<Variant>>,
     pub ast_id: FileAstId<ast::Enum>,
 }
 
diff --git a/crates/hir-def/src/item_tree/lower.rs b/crates/hir-def/src/item_tree/lower.rs
index 6343b43a016..f6086ed6d9b 100644
--- a/crates/hir-def/src/item_tree/lower.rs
+++ b/crates/hir-def/src/item_tree/lower.rs
@@ -13,7 +13,7 @@ use crate::{
 
 use super::*;
 
-fn id<N: ItemTreeNode>(index: Idx<N>) -> FileItemTreeId<N> {
+fn id<N: ItemTreeModItemNode>(index: Idx<N>) -> FileItemTreeId<N> {
     FileItemTreeId(index)
 }
 
@@ -253,25 +253,27 @@ impl<'a> Ctx<'a> {
         let generic_params = self.lower_generic_params(HasImplicitSelf::No, enum_);
         let variants = match &enum_.variant_list() {
             Some(variant_list) => self.lower_variants(variant_list),
-            None => IdxRange::new(self.next_variant_idx()..self.next_variant_idx()),
+            None => {
+                FileItemTreeId(self.next_variant_idx())..FileItemTreeId(self.next_variant_idx())
+            }
         };
         let res = Enum { name, visibility, generic_params, variants, ast_id };
         Some(id(self.data().enums.alloc(res)))
     }
 
-    fn lower_variants(&mut self, variants: &ast::VariantList) -> IdxRange<Variant> {
+    fn lower_variants(&mut self, variants: &ast::VariantList) -> Range<FileItemTreeId<Variant>> {
         let start = self.next_variant_idx();
         for variant in variants.variants() {
             if let Some(data) = self.lower_variant(&variant) {
                 let idx = self.data().variants.alloc(data);
                 self.add_attrs(
-                    idx.into(),
+                    FileItemTreeId(idx).into(),
                     RawAttrs::new(self.db.upcast(), &variant, self.span_map()),
                 );
             }
         }
         let end = self.next_variant_idx();
-        IdxRange::new(start..end)
+        FileItemTreeId(start)..FileItemTreeId(end)
     }
 
     fn lower_variant(&mut self, variant: &ast::Variant) -> Option<Variant> {
diff --git a/crates/hir-def/src/item_tree/pretty.rs b/crates/hir-def/src/item_tree/pretty.rs
index 8693b9a98c9..d8a0cb56983 100644
--- a/crates/hir-def/src/item_tree/pretty.rs
+++ b/crates/hir-def/src/item_tree/pretty.rs
@@ -318,7 +318,7 @@ impl Printer<'_> {
                 self.print_generic_params(generic_params);
                 self.print_where_clause_and_opening_brace(generic_params);
                 self.indented(|this| {
-                    for variant in variants.clone() {
+                    for variant in FileItemTreeId::range_iter(variants.clone()) {
                         let Variant { name, fields, ast_id: _ } = &this.tree[variant];
                         this.print_attrs_of(variant, "\n");
                         w!(this, "{}", name.display(self.db.upcast()));
diff --git a/crates/hir-def/src/lang_item.rs b/crates/hir-def/src/lang_item.rs
index 1a3f53c383b..45ba939b8cf 100644
--- a/crates/hir-def/src/lang_item.rs
+++ b/crates/hir-def/src/lang_item.rs
@@ -125,12 +125,8 @@ impl LangItems {
                     }
                     ModuleDefId::AdtId(AdtId::EnumId(e)) => {
                         lang_items.collect_lang_item(db, e, LangItemTarget::EnumId);
-                        db.enum_data(e).variants.iter().for_each(|(local_id, _)| {
-                            lang_items.collect_lang_item(
-                                db,
-                                EnumVariantId { parent: e, local_id },
-                                LangItemTarget::EnumVariant,
-                            );
+                        crate_def_map.enum_definitions[&e].iter().for_each(|&id| {
+                            lang_items.collect_lang_item(db, id, LangItemTarget::EnumVariant);
                         });
                     }
                     ModuleDefId::AdtId(AdtId::StructId(s)) => {
diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs
index aa84ccaee6e..bcd1f37bec4 100644
--- a/crates/hir-def/src/lib.rs
+++ b/crates/hir-def/src/lib.rs
@@ -99,8 +99,8 @@ use crate::{
     data::adt::VariantData,
     db::DefDatabase,
     item_tree::{
-        Const, Enum, ExternCrate, Function, Impl, ItemTreeId, ItemTreeNode, Macro2, MacroRules,
-        Static, Struct, Trait, TraitAlias, TypeAlias, Union, Use,
+        Const, Enum, ExternCrate, Function, Impl, ItemTreeId, ItemTreeModItemNode, Macro2,
+        MacroRules, Static, Struct, Trait, TraitAlias, TypeAlias, Union, Use, Variant,
     },
 };
 
@@ -213,28 +213,28 @@ impl ModuleId {
 pub type LocalModuleId = Idx<nameres::ModuleData>;
 
 #[derive(Debug)]
-pub struct ItemLoc<N: ItemTreeNode> {
+pub struct ItemLoc<N: ItemTreeModItemNode> {
     pub container: ModuleId,
     pub id: ItemTreeId<N>,
 }
 
-impl<N: ItemTreeNode> Clone for ItemLoc<N> {
+impl<N: ItemTreeModItemNode> Clone for ItemLoc<N> {
     fn clone(&self) -> Self {
         Self { container: self.container, id: self.id }
     }
 }
 
-impl<N: ItemTreeNode> Copy for ItemLoc<N> {}
+impl<N: ItemTreeModItemNode> Copy for ItemLoc<N> {}
 
-impl<N: ItemTreeNode> PartialEq for ItemLoc<N> {
+impl<N: ItemTreeModItemNode> PartialEq for ItemLoc<N> {
     fn eq(&self, other: &Self) -> bool {
         self.container == other.container && self.id == other.id
     }
 }
 
-impl<N: ItemTreeNode> Eq for ItemLoc<N> {}
+impl<N: ItemTreeModItemNode> Eq for ItemLoc<N> {}
 
-impl<N: ItemTreeNode> Hash for ItemLoc<N> {
+impl<N: ItemTreeModItemNode> Hash for ItemLoc<N> {
     fn hash<H: Hasher>(&self, state: &mut H) {
         self.container.hash(state);
         self.id.hash(state);
@@ -242,28 +242,28 @@ impl<N: ItemTreeNode> Hash for ItemLoc<N> {
 }
 
 #[derive(Debug)]
-pub struct AssocItemLoc<N: ItemTreeNode> {
+pub struct AssocItemLoc<N: ItemTreeModItemNode> {
     pub container: ItemContainerId,
     pub id: ItemTreeId<N>,
 }
 
-impl<N: ItemTreeNode> Clone for AssocItemLoc<N> {
+impl<N: ItemTreeModItemNode> Clone for AssocItemLoc<N> {
     fn clone(&self) -> Self {
         Self { container: self.container, id: self.id }
     }
 }
 
-impl<N: ItemTreeNode> Copy for AssocItemLoc<N> {}
+impl<N: ItemTreeModItemNode> Copy for AssocItemLoc<N> {}
 
-impl<N: ItemTreeNode> PartialEq for AssocItemLoc<N> {
+impl<N: ItemTreeModItemNode> PartialEq for AssocItemLoc<N> {
     fn eq(&self, other: &Self) -> bool {
         self.container == other.container && self.id == other.id
     }
 }
 
-impl<N: ItemTreeNode> Eq for AssocItemLoc<N> {}
+impl<N: ItemTreeModItemNode> Eq for AssocItemLoc<N> {}
 
-impl<N: ItemTreeNode> Hash for AssocItemLoc<N> {
+impl<N: ItemTreeModItemNode> Hash for AssocItemLoc<N> {
     fn hash<H: Hasher>(&self, state: &mut H) {
         self.container.hash(state);
         self.id.hash(state);
@@ -297,14 +297,16 @@ pub struct EnumId(salsa::InternId);
 pub type EnumLoc = ItemLoc<Enum>;
 impl_intern!(EnumId, EnumLoc, intern_enum, lookup_intern_enum);
 
-// FIXME: rename to `VariantId`, only enums can ave variants
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub struct EnumVariantId {
+pub struct EnumVariantId(salsa::InternId);
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct EnumVariantLoc {
+    pub id: ItemTreeId<Variant>,
     pub parent: EnumId,
-    pub local_id: LocalEnumVariantId,
+    pub index: u32,
 }
-
-pub type LocalEnumVariantId = Idx<data::adt::EnumVariantData>;
+impl_intern!(EnumVariantId, EnumVariantLoc, intern_enum_variant, lookup_intern_enum_variant);
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct FieldId {
@@ -953,23 +955,21 @@ impl VariantId {
         match self {
             VariantId::StructId(it) => db.struct_data(it).variant_data.clone(),
             VariantId::UnionId(it) => db.union_data(it).variant_data.clone(),
-            VariantId::EnumVariantId(it) => {
-                db.enum_data(it.parent).variants[it.local_id].variant_data.clone()
-            }
+            VariantId::EnumVariantId(it) => db.enum_variant_data(it).variant_data.clone(),
         }
     }
 
     pub fn file_id(self, db: &dyn DefDatabase) -> HirFileId {
         match self {
-            VariantId::EnumVariantId(it) => it.parent.lookup(db).id.file_id(),
+            VariantId::EnumVariantId(it) => it.lookup(db).id.file_id(),
             VariantId::StructId(it) => it.lookup(db).id.file_id(),
             VariantId::UnionId(it) => it.lookup(db).id.file_id(),
         }
     }
 
-    pub fn adt_id(self) -> AdtId {
+    pub fn adt_id(self, db: &dyn DefDatabase) -> AdtId {
         match self {
-            VariantId::EnumVariantId(it) => it.parent.into(),
+            VariantId::EnumVariantId(it) => it.lookup(db).parent.into(),
             VariantId::StructId(it) => it.into(),
             VariantId::UnionId(it) => it.into(),
         }
@@ -991,7 +991,8 @@ impl HasModule for ItemContainerId {
     }
 }
 
-impl<N: ItemTreeNode> HasModule for AssocItemLoc<N> {
+impl<N: ItemTreeModItemNode> HasModule for AssocItemLoc<N> {
+    #[inline]
     fn module(&self, db: &dyn DefDatabase) -> ModuleId {
         self.container.module(db)
     }
@@ -1007,7 +1008,22 @@ impl HasModule for AdtId {
     }
 }
 
+impl HasModule for EnumId {
+    #[inline]
+    fn module(&self, db: &dyn DefDatabase) -> ModuleId {
+        self.lookup(db).container
+    }
+}
+
+impl HasModule for EnumVariantId {
+    #[inline]
+    fn module(&self, db: &dyn DefDatabase) -> ModuleId {
+        self.lookup(db).parent.module(db)
+    }
+}
+
 impl HasModule for ExternCrateId {
+    #[inline]
     fn module(&self, db: &dyn DefDatabase) -> ModuleId {
         self.lookup(db).container
     }
@@ -1016,7 +1032,7 @@ impl HasModule for ExternCrateId {
 impl HasModule for VariantId {
     fn module(&self, db: &dyn DefDatabase) -> ModuleId {
         match self {
-            VariantId::EnumVariantId(it) => it.parent.lookup(db).container,
+            VariantId::EnumVariantId(it) => it.lookup(db).parent.module(db),
             VariantId::StructId(it) => it.lookup(db).container,
             VariantId::UnionId(it) => it.lookup(db).container,
         }
@@ -1045,7 +1061,7 @@ impl HasModule for TypeOwnerId {
             TypeOwnerId::TraitAliasId(it) => it.lookup(db).container,
             TypeOwnerId::TypeAliasId(it) => it.lookup(db).module(db),
             TypeOwnerId::ImplId(it) => it.lookup(db).container,
-            TypeOwnerId::EnumVariantId(it) => it.parent.lookup(db).container,
+            TypeOwnerId::EnumVariantId(it) => it.lookup(db).parent.module(db),
         }
     }
 }
@@ -1056,7 +1072,7 @@ impl HasModule for DefWithBodyId {
             DefWithBodyId::FunctionId(it) => it.lookup(db).module(db),
             DefWithBodyId::StaticId(it) => it.lookup(db).module(db),
             DefWithBodyId::ConstId(it) => it.lookup(db).module(db),
-            DefWithBodyId::VariantId(it) => it.parent.lookup(db).container,
+            DefWithBodyId::VariantId(it) => it.lookup(db).parent.module(db),
             DefWithBodyId::InTypeConstId(it) => it.lookup(db).owner.module(db),
         }
     }
@@ -1071,19 +1087,21 @@ impl HasModule for GenericDefId {
             GenericDefId::TraitAliasId(it) => it.lookup(db).container,
             GenericDefId::TypeAliasId(it) => it.lookup(db).module(db),
             GenericDefId::ImplId(it) => it.lookup(db).container,
-            GenericDefId::EnumVariantId(it) => it.parent.lookup(db).container,
+            GenericDefId::EnumVariantId(it) => it.lookup(db).parent.lookup(db).container,
             GenericDefId::ConstId(it) => it.lookup(db).module(db),
         }
     }
 }
 
 impl HasModule for TypeAliasId {
+    #[inline]
     fn module(&self, db: &dyn DefDatabase) -> ModuleId {
         self.lookup(db).module(db)
     }
 }
 
 impl HasModule for TraitId {
+    #[inline]
     fn module(&self, db: &dyn DefDatabase) -> ModuleId {
         self.lookup(db).container
     }
@@ -1098,7 +1116,7 @@ impl ModuleDefId {
             ModuleDefId::ModuleId(id) => *id,
             ModuleDefId::FunctionId(id) => id.lookup(db).module(db),
             ModuleDefId::AdtId(id) => id.module(db),
-            ModuleDefId::EnumVariantId(id) => id.parent.lookup(db).container,
+            ModuleDefId::EnumVariantId(id) => id.lookup(db).parent.module(db),
             ModuleDefId::ConstId(id) => id.lookup(db).container.module(db),
             ModuleDefId::StaticId(id) => id.lookup(db).module(db),
             ModuleDefId::TraitId(id) => id.lookup(db).container,
@@ -1117,7 +1135,7 @@ impl AttrDefId {
             AttrDefId::FieldId(it) => it.parent.module(db).krate,
             AttrDefId::AdtId(it) => it.module(db).krate,
             AttrDefId::FunctionId(it) => it.lookup(db).module(db).krate,
-            AttrDefId::EnumVariantId(it) => it.parent.lookup(db).container.krate,
+            AttrDefId::EnumVariantId(it) => it.lookup(db).parent.module(db).krate,
             AttrDefId::StaticId(it) => it.lookup(db).module(db).krate,
             AttrDefId::ConstId(it) => it.lookup(db).module(db).krate,
             AttrDefId::TraitId(it) => it.lookup(db).container.krate,
diff --git a/crates/hir-def/src/nameres.rs b/crates/hir-def/src/nameres.rs
index 53644f58efc..7eb2f3adddb 100644
--- a/crates/hir-def/src/nameres.rs
+++ b/crates/hir-def/src/nameres.rs
@@ -80,8 +80,8 @@ use crate::{
     path::ModPath,
     per_ns::PerNs,
     visibility::{Visibility, VisibilityExplicity},
-    AstId, BlockId, BlockLoc, CrateRootModuleId, ExternCrateId, FunctionId, LocalModuleId, Lookup,
-    MacroExpander, MacroId, ModuleId, ProcMacroId, UseId,
+    AstId, BlockId, BlockLoc, CrateRootModuleId, EnumId, EnumVariantId, ExternCrateId, FunctionId,
+    LocalModuleId, Lookup, MacroExpander, MacroId, ModuleId, ProcMacroId, UseId,
 };
 
 /// Contains the results of (early) name resolution.
@@ -113,6 +113,7 @@ pub struct DefMap {
     /// this contains all kinds of macro, not just `macro_rules!` macro.
     /// ExternCrateId being None implies it being imported from the general prelude import.
     macro_use_prelude: FxHashMap<Name, (MacroId, Option<ExternCrateId>)>,
+    pub(crate) enum_definitions: FxHashMap<EnumId, Box<[EnumVariantId]>>,
 
     /// Tracks which custom derives are in scope for an item, to allow resolution of derive helper
     /// attributes.
@@ -370,6 +371,7 @@ impl DefMap {
             macro_use_prelude: FxHashMap::default(),
             derive_helpers_in_scope: FxHashMap::default(),
             diagnostics: Vec::new(),
+            enum_definitions: FxHashMap::default(),
             data: Arc::new(DefMapCrateData {
                 extern_prelude: FxHashMap::default(),
                 exported_derives: FxHashMap::default(),
@@ -612,12 +614,14 @@ impl DefMap {
             krate: _,
             prelude: _,
             data: _,
+            enum_definitions,
         } = self;
 
         macro_use_prelude.shrink_to_fit();
         diagnostics.shrink_to_fit();
         modules.shrink_to_fit();
         derive_helpers_in_scope.shrink_to_fit();
+        enum_definitions.shrink_to_fit();
         for (_, module) in modules.iter_mut() {
             module.children.shrink_to_fit();
             module.scope.shrink_to_fit();
diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs
index a18ac4b28c4..893ad47e241 100644
--- a/crates/hir-def/src/nameres/collector.rs
+++ b/crates/hir-def/src/nameres/collector.rs
@@ -3,7 +3,7 @@
 //! `DefCollector::collect` contains the fixed-point iteration loop which
 //! resolves imports and expands macros.
 
-use std::{cmp::Ordering, iter, mem};
+use std::{cmp::Ordering, iter, mem, ops::Not};
 
 use base_db::{CrateId, Dependency, Edition, FileId};
 use cfg::{CfgExpr, CfgOptions};
@@ -23,7 +23,7 @@ use itertools::{izip, Itertools};
 use la_arena::Idx;
 use limit::Limit;
 use rustc_hash::{FxHashMap, FxHashSet};
-use span::{Span, SyntaxContextId};
+use span::{ErasedFileAstId, Span, SyntaxContextId};
 use stdx::always;
 use syntax::{ast, SmolStr};
 use triomphe::Arc;
@@ -35,8 +35,8 @@ use crate::{
     derive_macro_as_call_id,
     item_scope::{ImportId, ImportOrExternCrate, ImportType, PerNsGlobImports},
     item_tree::{
-        self, ExternCrate, Fields, FileItemTreeId, ImportKind, ItemTree, ItemTreeId, ItemTreeNode,
-        Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, TreeId,
+        self, ExternCrate, Fields, FileItemTreeId, ImportKind, ItemTree, ItemTreeId,
+        ItemTreeModItemNode, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, TreeId,
     },
     macro_call_as_call_id, macro_call_as_call_id_with_eager,
     nameres::{
@@ -51,7 +51,7 @@ use crate::{
     per_ns::PerNs,
     tt,
     visibility::{RawVisibility, Visibility},
-    AdtId, AstId, AstIdWithPath, ConstLoc, CrateRootModuleId, EnumLoc, EnumVariantId,
+    AdtId, AstId, AstIdWithPath, ConstLoc, CrateRootModuleId, EnumLoc, EnumVariantLoc,
     ExternBlockLoc, ExternCrateId, ExternCrateLoc, FunctionId, FunctionLoc, ImplLoc, Intern,
     ItemContainerId, LocalModuleId, Lookup, Macro2Id, Macro2Loc, MacroExpander, MacroId,
     MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ModuleDefId, ModuleId, ProcMacroId,
@@ -980,24 +980,26 @@ impl DefCollector<'_> {
                         cov_mark::hit!(glob_enum);
                         // glob import from enum => just import all the variants
 
-                        // XXX: urgh, so this works by accident! Here, we look at
-                        // the enum data, and, in theory, this might require us to
-                        // look back at the crate_def_map, creating a cycle. For
-                        // example, `enum E { crate::some_macro!(); }`. Luckily, the
-                        // only kind of macro that is allowed inside enum is a
-                        // `cfg_macro`, and we don't need to run name resolution for
-                        // it, but this is sheer luck!
-                        let enum_data = self.db.enum_data(e);
-                        let resolutions = enum_data
-                            .variants
-                            .iter()
-                            .map(|(local_id, variant_data)| {
-                                let name = variant_data.name.clone();
-                                let variant = EnumVariantId { parent: e, local_id };
-                                let res = PerNs::both(variant.into(), variant.into(), vis, None);
-                                (Some(name), res)
-                            })
-                            .collect::<Vec<_>>();
+                        // We need to check if the def map the enum is from is us, if it is we can't
+                        // call the def-map query since we are currently constructing it!
+                        let loc = e.lookup(self.db);
+                        let tree = loc.id.item_tree(self.db);
+                        let current_def_map = self.def_map.krate == loc.container.krate
+                            && self.def_map.block_id() == loc.container.block;
+                        let def_map;
+                        let resolutions = if current_def_map {
+                            &self.def_map.enum_definitions[&e]
+                        } else {
+                            def_map = loc.container.def_map(self.db);
+                            &def_map.enum_definitions[&e]
+                        }
+                        .iter()
+                        .map(|&variant| {
+                            let name = tree[variant.lookup(self.db).id.value].name.clone();
+                            let res = PerNs::both(variant.into(), variant.into(), vis, None);
+                            (Some(name), res)
+                        })
+                        .collect::<Vec<_>>();
                         self.update(module_id, &resolutions, vis, Some(ImportType::Glob(id)));
                     }
                     Some(d) => {
@@ -1577,7 +1579,10 @@ impl ModCollector<'_, '_> {
             let attrs = self.item_tree.attrs(db, krate, item.into());
             if let Some(cfg) = attrs.cfg() {
                 if !self.is_cfg_enabled(&cfg) {
-                    self.emit_unconfigured_diagnostic(item, &cfg);
+                    self.emit_unconfigured_diagnostic(
+                        InFile::new(self.file_id(), item.ast_id(self.item_tree).erase()),
+                        &cfg,
+                    );
                     return;
                 }
             }
@@ -1708,17 +1713,47 @@ impl ModCollector<'_, '_> {
                 }
                 ModItem::Enum(id) => {
                     let it = &self.item_tree[id];
+                    let enum_ =
+                        EnumLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
+                            .intern(db);
 
                     let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
-                    update_def(
-                        self.def_collector,
-                        EnumLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
-                            .intern(db)
-                            .into(),
-                        &it.name,
-                        vis,
-                        false,
-                    );
+                    update_def(self.def_collector, enum_.into(), &it.name, vis, false);
+
+                    let mut index = 0;
+                    let variants = FileItemTreeId::range_iter(it.variants.clone())
+                        .filter_map(|variant| {
+                            let is_enabled = self
+                                .item_tree
+                                .attrs(db, krate, variant.into())
+                                .cfg()
+                                .and_then(|cfg| self.is_cfg_enabled(&cfg).not().then_some(cfg))
+                                .map_or(Ok(()), Err);
+                            match is_enabled {
+                                Err(cfg) => {
+                                    self.emit_unconfigured_diagnostic(
+                                        InFile::new(
+                                            self.file_id(),
+                                            self.item_tree[variant.index()].ast_id.erase(),
+                                        ),
+                                        &cfg,
+                                    );
+                                    None
+                                }
+                                Ok(()) => Some({
+                                    let loc = EnumVariantLoc {
+                                        id: ItemTreeId::new(self.tree_id, variant),
+                                        parent: enum_,
+                                        index,
+                                    }
+                                    .intern(db);
+                                    index += 1;
+                                    loc
+                                }),
+                            }
+                        })
+                        .collect();
+                    self.def_collector.def_map.enum_definitions.insert(enum_, variants);
                 }
                 ModItem::Const(id) => {
                     let it = &self.item_tree[id];
@@ -1905,31 +1940,40 @@ impl ModCollector<'_, '_> {
                         let is_enabled = item_tree
                             .top_level_attrs(db, krate)
                             .cfg()
-                            .map_or(true, |cfg| self.is_cfg_enabled(&cfg));
-                        if is_enabled {
-                            let module_id = self.push_child_module(
-                                module.name.clone(),
-                                ast_id.value,
-                                Some((file_id, is_mod_rs)),
-                                &self.item_tree[module.visibility],
-                                module_id,
-                            );
-                            ModCollector {
-                                def_collector: self.def_collector,
-                                macro_depth: self.macro_depth,
-                                module_id,
-                                tree_id: TreeId::new(file_id.into(), None),
-                                item_tree: &item_tree,
-                                mod_dir,
+                            .and_then(|cfg| self.is_cfg_enabled(&cfg).not().then_some(cfg))
+                            .map_or(Ok(()), Err);
+                        match is_enabled {
+                            Err(cfg) => {
+                                self.emit_unconfigured_diagnostic(
+                                    ast_id.map(|it| it.erase()),
+                                    &cfg,
+                                );
                             }
-                            .collect_in_top_module(item_tree.top_level_items());
-                            let is_macro_use = is_macro_use
-                                || item_tree
-                                    .top_level_attrs(db, krate)
-                                    .by_key("macro_use")
-                                    .exists();
-                            if is_macro_use {
-                                self.import_all_legacy_macros(module_id);
+                            Ok(()) => {
+                                let module_id = self.push_child_module(
+                                    module.name.clone(),
+                                    ast_id.value,
+                                    Some((file_id, is_mod_rs)),
+                                    &self.item_tree[module.visibility],
+                                    module_id,
+                                );
+                                ModCollector {
+                                    def_collector: self.def_collector,
+                                    macro_depth: self.macro_depth,
+                                    module_id,
+                                    tree_id: TreeId::new(file_id.into(), None),
+                                    item_tree: &item_tree,
+                                    mod_dir,
+                                }
+                                .collect_in_top_module(item_tree.top_level_items());
+                                let is_macro_use = is_macro_use
+                                    || item_tree
+                                        .top_level_attrs(db, krate)
+                                        .by_key("macro_use")
+                                        .exists();
+                                if is_macro_use {
+                                    self.import_all_legacy_macros(module_id);
+                                }
                             }
                         }
                     }
@@ -2360,10 +2404,7 @@ impl ModCollector<'_, '_> {
         self.def_collector.cfg_options.check(cfg) != Some(false)
     }
 
-    fn emit_unconfigured_diagnostic(&mut self, item: ModItem, cfg: &CfgExpr) {
-        let ast_id = item.ast_id(self.item_tree);
-
-        let ast_id = InFile::new(self.file_id(), ast_id.erase());
+    fn emit_unconfigured_diagnostic(&mut self, ast_id: InFile<ErasedFileAstId>, cfg: &CfgExpr) {
         self.def_collector.def_map.diagnostics.push(DefDiagnostic::unconfigured_code(
             self.module_id,
             ast_id,
diff --git a/crates/hir-def/src/nameres/diagnostics.rs b/crates/hir-def/src/nameres/diagnostics.rs
index 9cffb3c9f37..0a3f7bf7ec3 100644
--- a/crates/hir-def/src/nameres/diagnostics.rs
+++ b/crates/hir-def/src/nameres/diagnostics.rs
@@ -40,6 +40,23 @@ pub enum DefDiagnosticKind {
     MacroDefError { ast: AstId<ast::Macro>, message: String },
 }
 
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct DefDiagnostics(Option<triomphe::Arc<Box<[DefDiagnostic]>>>);
+
+impl DefDiagnostics {
+    pub fn new(diagnostics: Vec<DefDiagnostic>) -> Self {
+        Self(if diagnostics.is_empty() {
+            None
+        } else {
+            Some(triomphe::Arc::new(diagnostics.into_boxed_slice()))
+        })
+    }
+
+    pub fn iter(&self) -> impl Iterator<Item = &DefDiagnostic> {
+        self.0.as_ref().into_iter().flat_map(|it| &***it)
+    }
+}
+
 #[derive(Debug, PartialEq, Eq)]
 pub struct DefDiagnostic {
     pub in_module: LocalModuleId,
diff --git a/crates/hir-def/src/nameres/path_resolution.rs b/crates/hir-def/src/nameres/path_resolution.rs
index 389dabdbc86..01f79f042f7 100644
--- a/crates/hir-def/src/nameres/path_resolution.rs
+++ b/crates/hir-def/src/nameres/path_resolution.rs
@@ -11,18 +11,18 @@
 //! `ReachedFixedPoint` signals about this.
 
 use base_db::Edition;
-use hir_expand::name::Name;
+use hir_expand::{name::Name, Lookup};
 use triomphe::Arc;
 
 use crate::{
-    data::adt::VariantData,
     db::DefDatabase,
     item_scope::{ImportOrExternCrate, BUILTIN_SCOPE},
+    item_tree::Fields,
     nameres::{sub_namespace_match, BlockInfo, BuiltinShadowMode, DefMap, MacroSubNs},
     path::{ModPath, PathKind},
     per_ns::PerNs,
     visibility::{RawVisibility, Visibility},
-    AdtId, CrateId, EnumVariantId, LocalModuleId, ModuleDefId,
+    AdtId, CrateId, LocalModuleId, ModuleDefId,
 };
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -355,29 +355,42 @@ impl DefMap {
                 ModuleDefId::AdtId(AdtId::EnumId(e)) => {
                     // enum variant
                     cov_mark::hit!(can_import_enum_variant);
-                    let enum_data = db.enum_data(e);
-                    match enum_data.variant(segment) {
-                        Some(local_id) => {
-                            let variant = EnumVariantId { parent: e, local_id };
-                            match &*enum_data.variants[local_id].variant_data {
-                                VariantData::Record(_) => {
-                                    PerNs::types(variant.into(), Visibility::Public, None)
-                                }
-                                VariantData::Tuple(_) | VariantData::Unit => PerNs::both(
-                                    variant.into(),
-                                    variant.into(),
-                                    Visibility::Public,
-                                    None,
-                                ),
+                    let def_map;
+
+                    let loc = e.lookup(db);
+                    let tree = loc.id.item_tree(db);
+                    let current_def_map =
+                        self.krate == loc.container.krate && self.block_id() == loc.container.block;
+                    let res = if current_def_map {
+                        &self.enum_definitions[&e]
+                    } else {
+                        def_map = loc.container.def_map(db);
+                        &def_map.enum_definitions[&e]
+                    }
+                    .iter()
+                    .find_map(|&variant| {
+                        let variant_data = &tree[variant.lookup(db).id.value];
+                        (variant_data.name == *segment).then(|| match variant_data.fields {
+                            Fields::Record(_) => {
+                                PerNs::types(variant.into(), Visibility::Public, None)
                             }
-                        }
+                            Fields::Tuple(_) | Fields::Unit => PerNs::both(
+                                variant.into(),
+                                variant.into(),
+                                Visibility::Public,
+                                None,
+                            ),
+                        })
+                    });
+                    match res {
+                        Some(res) => res,
                         None => {
                             return ResolvePathResult::with(
                                 PerNs::types(e.into(), vis, imp),
                                 ReachedFixedPoint::Yes,
                                 Some(i),
                                 Some(self.krate),
-                            );
+                            )
                         }
                     }
                 }
diff --git a/crates/hir-def/src/pretty.rs b/crates/hir-def/src/pretty.rs
index f4f5541e373..8e0df469701 100644
--- a/crates/hir-def/src/pretty.rs
+++ b/crates/hir-def/src/pretty.rs
@@ -39,11 +39,9 @@ pub(crate) fn print_path(db: &dyn DefDatabase, path: &Path, buf: &mut dyn Write)
             LangItemTarget::Trait(it) => {
                 write!(buf, "{}", db.trait_data(it).name.display(db.upcast()))?
             }
-            LangItemTarget::EnumVariant(it) => write!(
-                buf,
-                "{}",
-                db.enum_data(it.parent).variants[it.local_id].name.display(db.upcast())
-            )?,
+            LangItemTarget::EnumVariant(it) => {
+                write!(buf, "{}", db.enum_variant_data(it).name.display(db.upcast()))?
+            }
         }
 
         if let Some(s) = s {
diff --git a/crates/hir-def/src/resolver.rs b/crates/hir-def/src/resolver.rs
index 1d850f721c1..bb530259ac5 100644
--- a/crates/hir-def/src/resolver.rs
+++ b/crates/hir-def/src/resolver.rs
@@ -1111,7 +1111,7 @@ impl HasResolver for DefWithBodyId {
             DefWithBodyId::ConstId(c) => c.resolver(db),
             DefWithBodyId::FunctionId(f) => f.resolver(db),
             DefWithBodyId::StaticId(s) => s.resolver(db),
-            DefWithBodyId::VariantId(v) => v.parent.resolver(db),
+            DefWithBodyId::VariantId(v) => v.resolver(db),
             DefWithBodyId::InTypeConstId(c) => c.lookup(db).owner.resolver(db),
         }
     }
@@ -1137,7 +1137,7 @@ impl HasResolver for GenericDefId {
             GenericDefId::TraitAliasId(inner) => inner.resolver(db),
             GenericDefId::TypeAliasId(inner) => inner.resolver(db),
             GenericDefId::ImplId(inner) => inner.resolver(db),
-            GenericDefId::EnumVariantId(inner) => inner.parent.resolver(db),
+            GenericDefId::EnumVariantId(inner) => inner.resolver(db),
             GenericDefId::ConstId(inner) => inner.resolver(db),
         }
     }
@@ -1145,14 +1145,14 @@ impl HasResolver for GenericDefId {
 
 impl HasResolver for EnumVariantId {
     fn resolver(self, db: &dyn DefDatabase) -> Resolver {
-        self.parent.resolver(db)
+        self.lookup(db).parent.resolver(db)
     }
 }
 
 impl HasResolver for VariantId {
     fn resolver(self, db: &dyn DefDatabase) -> Resolver {
         match self {
-            VariantId::EnumVariantId(it) => it.parent.resolver(db),
+            VariantId::EnumVariantId(it) => it.resolver(db),
             VariantId::StructId(it) => it.resolver(db),
             VariantId::UnionId(it) => it.resolver(db),
         }
diff --git a/crates/hir-def/src/src.rs b/crates/hir-def/src/src.rs
index 3770103cda5..9bd8c8d2215 100644
--- a/crates/hir-def/src/src.rs
+++ b/crates/hir-def/src/src.rs
@@ -5,8 +5,8 @@ use la_arena::ArenaMap;
 use syntax::ast;
 
 use crate::{
-    db::DefDatabase, item_tree::ItemTreeNode, AssocItemLoc, ItemLoc, Lookup, Macro2Loc,
-    MacroRulesLoc, ProcMacroLoc, UseId,
+    db::DefDatabase, item_tree::ItemTreeModItemNode, AssocItemLoc, EnumVariantLoc, ItemLoc, Lookup,
+    Macro2Loc, MacroRulesLoc, ProcMacroLoc, UseId,
 };
 
 pub trait HasSource {
@@ -14,7 +14,7 @@ pub trait HasSource {
     fn source(&self, db: &dyn DefDatabase) -> InFile<Self::Value>;
 }
 
-impl<N: ItemTreeNode> HasSource for AssocItemLoc<N> {
+impl<N: ItemTreeModItemNode> HasSource for AssocItemLoc<N> {
     type Value = N::Source;
 
     fn source(&self, db: &dyn DefDatabase) -> InFile<N::Source> {
@@ -27,7 +27,7 @@ impl<N: ItemTreeNode> HasSource for AssocItemLoc<N> {
     }
 }
 
-impl<N: ItemTreeNode> HasSource for ItemLoc<N> {
+impl<N: ItemTreeModItemNode> HasSource for ItemLoc<N> {
     type Value = N::Source;
 
     fn source(&self, db: &dyn DefDatabase) -> InFile<N::Source> {
@@ -40,6 +40,19 @@ impl<N: ItemTreeNode> HasSource for ItemLoc<N> {
     }
 }
 
+impl HasSource for EnumVariantLoc {
+    type Value = ast::Variant;
+
+    fn source(&self, db: &dyn DefDatabase) -> InFile<ast::Variant> {
+        let tree = self.id.item_tree(db);
+        let ast_id_map = db.ast_id_map(self.id.file_id());
+        let root = db.parse_or_expand(self.id.file_id());
+        let node = &tree[self.id.value];
+
+        InFile::new(self.id.file_id(), ast_id_map.get(node.ast_id).to_node(&root))
+    }
+}
+
 impl HasSource for Macro2Loc {
     type Value = ast::MacroDef;
 
diff --git a/crates/hir-def/src/trace.rs b/crates/hir-def/src/trace.rs
index 6e6ceb8e474..04d5b266194 100644
--- a/crates/hir-def/src/trace.rs
+++ b/crates/hir-def/src/trace.rs
@@ -18,6 +18,7 @@ pub(crate) struct Trace<T, V> {
 }
 
 impl<T, V> Trace<T, V> {
+    #[allow(dead_code)]
     pub(crate) fn new_for_arena() -> Trace<T, V> {
         Trace { arena: Some(Arena::default()), map: None, len: 0 }
     }
@@ -41,6 +42,7 @@ impl<T, V> Trace<T, V> {
         id
     }
 
+    #[allow(dead_code)]
     pub(crate) fn into_arena(mut self) -> Arena<T> {
         self.arena.take().unwrap()
     }
diff --git a/crates/hir-def/src/visibility.rs b/crates/hir-def/src/visibility.rs
index cd8023f5d7d..3294ce29a4a 100644
--- a/crates/hir-def/src/visibility.rs
+++ b/crates/hir-def/src/visibility.rs
@@ -222,13 +222,7 @@ pub(crate) fn field_visibilities_query(
     db: &dyn DefDatabase,
     variant_id: VariantId,
 ) -> Arc<ArenaMap<LocalFieldId, Visibility>> {
-    let var_data = match variant_id {
-        VariantId::StructId(it) => db.struct_data(it).variant_data.clone(),
-        VariantId::UnionId(it) => db.union_data(it).variant_data.clone(),
-        VariantId::EnumVariantId(it) => {
-            db.enum_data(it.parent).variants[it.local_id].variant_data.clone()
-        }
-    };
+    let var_data = variant_id.variant_data(db);
     let resolver = variant_id.module(db).resolver(db);
     let mut res = ArenaMap::default();
     for (field_id, field_data) in var_data.fields().iter() {
diff --git a/crates/hir-expand/src/db.rs b/crates/hir-expand/src/db.rs
index ed04582cb0a..035664c6446 100644
--- a/crates/hir-expand/src/db.rs
+++ b/crates/hir-expand/src/db.rs
@@ -218,6 +218,9 @@ pub fn real_span_map(db: &dyn ExpandDatabase, file_id: FileId) -> Arc<RealSpanMa
     let mut pairs = vec![(syntax::TextSize::new(0), span::ROOT_ERASED_FILE_AST_ID)];
     let ast_id_map = db.ast_id_map(file_id.into());
     let tree = db.parse(file_id).tree();
+    // FIXME: Descend into modules and other item containing items that are not annotated with attributes
+    // and allocate pairs for those as well. This gives us finer grained span anchors resulting in
+    // better incrementality
     pairs.extend(
         tree.items()
             .map(|item| (item.syntax().text_range().start(), ast_id_map.ast_id(&item).erase())),
diff --git a/crates/hir-ty/src/consteval.rs b/crates/hir-ty/src/consteval.rs
index 5528ad3ab4a..dae612e6d25 100644
--- a/crates/hir-ty/src/consteval.rs
+++ b/crates/hir-ty/src/consteval.rs
@@ -10,7 +10,7 @@ use hir_def::{
     type_ref::LiteralConstRef,
     ConstBlockLoc, EnumVariantId, GeneralConstId, StaticId,
 };
-use la_arena::{Idx, RawIdx};
+use hir_expand::Lookup;
 use stdx::never;
 use triomphe::Arc;
 
@@ -256,12 +256,13 @@ pub(crate) fn const_eval_discriminant_variant(
     let def = variant_id.into();
     let body = db.body(def);
     if body.exprs[body.body_expr] == Expr::Missing {
-        let prev_idx: u32 = variant_id.local_id.into_raw().into();
-        let prev_idx = prev_idx.checked_sub(1).map(RawIdx::from).map(Idx::from_raw);
+        let loc = variant_id.lookup(db.upcast());
+        let prev_idx = loc.index.checked_sub(1);
         let value = match prev_idx {
-            Some(local_id) => {
-                let prev_variant = EnumVariantId { local_id, parent: variant_id.parent };
-                1 + db.const_eval_discriminant(prev_variant)?
+            Some(prev_idx) => {
+                1 + db.const_eval_discriminant(
+                    db.enum_data(loc.parent).variants[prev_idx as usize].0,
+                )?
             }
             _ => 0,
         };
diff --git a/crates/hir-ty/src/db.rs b/crates/hir-ty/src/db.rs
index 726069f20c0..9fc76550aa6 100644
--- a/crates/hir-ty/src/db.rs
+++ b/crates/hir-ty/src/db.rs
@@ -292,7 +292,7 @@ fn infer_wait(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<InferenceResult>
             .display(db.upcast())
             .to_string(),
         DefWithBodyId::VariantId(it) => {
-            db.enum_data(it.parent).variants[it.local_id].name.display(db.upcast()).to_string()
+            db.enum_variant_data(it).name.display(db.upcast()).to_string()
         }
         DefWithBodyId::InTypeConstId(it) => format!("in type const {it:?}"),
     });
diff --git a/crates/hir-ty/src/diagnostics/decl_check.rs b/crates/hir-ty/src/diagnostics/decl_check.rs
index 51a044d8ef5..7ea1b9e4213 100644
--- a/crates/hir-ty/src/diagnostics/decl_check.rs
+++ b/crates/hir-ty/src/diagnostics/decl_check.rs
@@ -582,11 +582,11 @@ impl<'a> DeclValidator<'a> {
         // Check the field names.
         let enum_fields_replacements = data
             .variants
-            .values()
-            .filter_map(|variant| {
+            .iter()
+            .filter_map(|(_, name)| {
                 Some(Replacement {
-                    current_name: variant.name.clone(),
-                    suggested_text: to_camel_case(&variant.name.to_smol_str())?,
+                    current_name: name.clone(),
+                    suggested_text: to_camel_case(&name.to_smol_str())?,
                     expected_case: CaseType::UpperCamelCase,
                 })
             })
diff --git a/crates/hir-ty/src/diagnostics/match_check.rs b/crates/hir-ty/src/diagnostics/match_check.rs
index 2e04bbfee83..e4d4536fc93 100644
--- a/crates/hir-ty/src/diagnostics/match_check.rs
+++ b/crates/hir-ty/src/diagnostics/match_check.rs
@@ -318,8 +318,7 @@ impl HirDisplay for Pat {
                 if let Some(variant) = variant {
                     match variant {
                         VariantId::EnumVariantId(v) => {
-                            let data = f.db.enum_data(v.parent);
-                            write!(f, "{}", data.variants[v.local_id].name.display(f.db.upcast()))?;
+                            write!(f, "{}", f.db.enum_variant_data(v).name.display(f.db.upcast()))?;
                         }
                         VariantId::StructId(s) => {
                             write!(f, "{}", f.db.struct_data(s).name.display(f.db.upcast()))?
diff --git a/crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs b/crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs
index a0f6b9368ee..f066f8b798d 100644
--- a/crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs
+++ b/crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs
@@ -594,7 +594,7 @@ impl SplitWildcard {
                 let mut ctors: SmallVec<[_; 1]> = enum_data
                     .variants
                     .iter()
-                    .map(|(local_id, _)| EnumVariantId { parent: *enum_id, local_id })
+                    .map(|&(variant, _)| variant)
                     .filter(|&variant| {
                         // If `exhaustive_patterns` is enabled, we exclude variants known to be
                         // uninhabited.
diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs
index e2ba221cf12..3a0ec6a582c 100644
--- a/crates/hir-ty/src/display.rs
+++ b/crates/hir-ty/src/display.rs
@@ -20,8 +20,7 @@ use hir_def::{
     path::{Path, PathKind},
     type_ref::{TraitBoundModifier, TypeBound, TypeRef},
     visibility::Visibility,
-    EnumVariantId, HasModule, ItemContainerId, LocalFieldId, Lookup, ModuleDefId, ModuleId,
-    TraitId,
+    HasModule, ItemContainerId, LocalFieldId, Lookup, ModuleDefId, ModuleId, TraitId,
 };
 use hir_expand::name::Name;
 use intern::{Internable, Interned};
@@ -613,10 +612,9 @@ fn render_const_scalar(
                     else {
                         return f.write_str("<failed-to-detect-variant>");
                     };
-                    let data = &f.db.enum_data(e).variants[var_id];
+                    let data = f.db.enum_variant_data(var_id);
                     write!(f, "{}", data.name.display(f.db.upcast()))?;
-                    let field_types =
-                        f.db.field_types(EnumVariantId { parent: e, local_id: var_id }.into());
+                    let field_types = f.db.field_types(var_id.into());
                     render_variant_after_name(
                         &data.variant_data,
                         f,
@@ -892,11 +890,9 @@ impl HirDisplay for Ty {
                     CallableDefId::StructId(s) => {
                         write!(f, "{}", db.struct_data(s).name.display(f.db.upcast()))?
                     }
-                    CallableDefId::EnumVariantId(e) => write!(
-                        f,
-                        "{}",
-                        db.enum_data(e.parent).variants[e.local_id].name.display(f.db.upcast())
-                    )?,
+                    CallableDefId::EnumVariantId(e) => {
+                        write!(f, "{}", db.enum_variant_data(e).name.display(f.db.upcast()))?
+                    }
                 };
                 f.end_location_link();
                 if parameters.len(Interner) > 0 {
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index 3de39584404..2aff53a4acd 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -40,8 +40,8 @@ use hir_def::{
     path::{ModPath, Path},
     resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs},
     type_ref::TypeRef,
-    AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, ItemContainerId, Lookup,
-    TraitId, TupleFieldId, TupleId, TypeAliasId, VariantId,
+    AdtId, AssocItemId, DefWithBodyId, FieldId, FunctionId, ItemContainerId, Lookup, TraitId,
+    TupleFieldId, TupleId, TypeAliasId, VariantId,
 };
 use hir_expand::name::{name, Name};
 use indexmap::IndexSet;
@@ -87,28 +87,30 @@ pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<Infer
         DefWithBodyId::ConstId(c) => ctx.collect_const(&db.const_data(c)),
         DefWithBodyId::StaticId(s) => ctx.collect_static(&db.static_data(s)),
         DefWithBodyId::VariantId(v) => {
-            ctx.return_ty = TyBuilder::builtin(match db.enum_data(v.parent).variant_body_type() {
-                hir_def::layout::IntegerType::Pointer(signed) => match signed {
-                    true => BuiltinType::Int(BuiltinInt::Isize),
-                    false => BuiltinType::Uint(BuiltinUint::Usize),
+            ctx.return_ty = TyBuilder::builtin(
+                match db.enum_data(v.lookup(db.upcast()).parent.into()).variant_body_type() {
+                    hir_def::layout::IntegerType::Pointer(signed) => match signed {
+                        true => BuiltinType::Int(BuiltinInt::Isize),
+                        false => BuiltinType::Uint(BuiltinUint::Usize),
+                    },
+                    hir_def::layout::IntegerType::Fixed(size, signed) => match signed {
+                        true => BuiltinType::Int(match size {
+                            Integer::I8 => BuiltinInt::I8,
+                            Integer::I16 => BuiltinInt::I16,
+                            Integer::I32 => BuiltinInt::I32,
+                            Integer::I64 => BuiltinInt::I64,
+                            Integer::I128 => BuiltinInt::I128,
+                        }),
+                        false => BuiltinType::Uint(match size {
+                            Integer::I8 => BuiltinUint::U8,
+                            Integer::I16 => BuiltinUint::U16,
+                            Integer::I32 => BuiltinUint::U32,
+                            Integer::I64 => BuiltinUint::U64,
+                            Integer::I128 => BuiltinUint::U128,
+                        }),
+                    },
                 },
-                hir_def::layout::IntegerType::Fixed(size, signed) => match signed {
-                    true => BuiltinType::Int(match size {
-                        Integer::I8 => BuiltinInt::I8,
-                        Integer::I16 => BuiltinInt::I16,
-                        Integer::I32 => BuiltinInt::I32,
-                        Integer::I64 => BuiltinInt::I64,
-                        Integer::I128 => BuiltinInt::I128,
-                    }),
-                    false => BuiltinType::Uint(match size {
-                        Integer::I8 => BuiltinUint::U8,
-                        Integer::I16 => BuiltinUint::U16,
-                        Integer::I32 => BuiltinUint::U32,
-                        Integer::I64 => BuiltinUint::U64,
-                        Integer::I128 => BuiltinUint::U128,
-                    }),
-                },
-            });
+            );
         }
         DefWithBodyId::InTypeConstId(c) => {
             // FIXME(const-generic-body): We should not get the return type in this way.
@@ -1062,7 +1064,7 @@ impl<'a> InferenceContext<'a> {
                 Some(ResolveValueResult::ValueNs(value, _)) => match value {
                     ValueNs::EnumVariantId(var) => {
                         let substs = ctx.substs_from_path(path, var.into(), true);
-                        let ty = self.db.ty(var.parent.into());
+                        let ty = self.db.ty(var.lookup(self.db.upcast()).parent.into());
                         let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
                         return (ty, Some(var.into()));
                     }
@@ -1105,7 +1107,7 @@ impl<'a> InferenceContext<'a> {
             }
             TypeNs::EnumVariantId(var) => {
                 let substs = ctx.substs_from_path(path, var.into(), true);
-                let ty = self.db.ty(var.parent.into());
+                let ty = self.db.ty(var.lookup(self.db.upcast()).parent.into());
                 let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
                 forbid_unresolved_segments((ty, Some(var.into())), unresolved)
             }
@@ -1131,8 +1133,7 @@ impl<'a> InferenceContext<'a> {
                     if let Some((AdtId::EnumId(id), _)) = ty.as_adt() {
                         let enum_data = self.db.enum_data(id);
                         let name = current_segment.first().unwrap().name;
-                        if let Some(local_id) = enum_data.variant(name) {
-                            let variant = EnumVariantId { parent: id, local_id };
+                        if let Some(variant) = enum_data.variant(name) {
                             return if remaining_segments.len() == 1 {
                                 (ty, Some(variant.into()))
                             } else {
@@ -1247,8 +1248,7 @@ impl<'a> InferenceContext<'a> {
                 // this could be an enum variant or associated type
                 if let Some((AdtId::EnumId(enum_id), _)) = ty.as_adt() {
                     let enum_data = self.db.enum_data(enum_id);
-                    if let Some(local_id) = enum_data.variant(segment) {
-                        let variant = EnumVariantId { parent: enum_id, local_id };
+                    if let Some(variant) = enum_data.variant(segment) {
                         return (ty, Some(variant.into()));
                     }
                 }
diff --git a/crates/hir-ty/src/infer/closure.rs b/crates/hir-ty/src/infer/closure.rs
index 3bf0a00cd11..c194270b91e 100644
--- a/crates/hir-ty/src/infer/closure.rs
+++ b/crates/hir-ty/src/infer/closure.rs
@@ -666,7 +666,7 @@ impl InferenceContext<'_> {
             | Pat::Or(_) => (),
             Pat::TupleStruct { .. } | Pat::Record { .. } => {
                 if let Some(variant) = self.result.variant_resolution_for_pat(p) {
-                    let adt = variant.adt_id();
+                    let adt = variant.adt_id(self.db.upcast());
                     let is_multivariant = match adt {
                         hir_def::AdtId::EnumId(e) => self.db.enum_data(e).variants.len() != 1,
                         _ => false,
diff --git a/crates/hir-ty/src/infer/path.rs b/crates/hir-ty/src/infer/path.rs
index e61a070265a..a09bb15147f 100644
--- a/crates/hir-ty/src/infer/path.rs
+++ b/crates/hir-ty/src/infer/path.rs
@@ -4,7 +4,7 @@ use chalk_ir::cast::Cast;
 use hir_def::{
     path::{Path, PathSegment},
     resolver::{ResolveValueResult, TypeNs, ValueNs},
-    AdtId, AssocItemId, EnumVariantId, GenericDefId, ItemContainerId, Lookup,
+    AdtId, AssocItemId, GenericDefId, ItemContainerId, Lookup,
 };
 use hir_expand::name::Name;
 use stdx::never;
@@ -395,8 +395,7 @@ impl InferenceContext<'_> {
             _ => return None,
         };
         let enum_data = self.db.enum_data(enum_id);
-        let local_id = enum_data.variant(name)?;
-        let variant = EnumVariantId { parent: enum_id, local_id };
+        let variant = enum_data.variant(name)?;
         self.write_variant_resolution(id, variant.into());
         Some((ValueNs::EnumVariantId(variant), subst.clone()))
     }
diff --git a/crates/hir-ty/src/inhabitedness.rs b/crates/hir-ty/src/inhabitedness.rs
index e5038543b68..a63556f450d 100644
--- a/crates/hir-ty/src/inhabitedness.rs
+++ b/crates/hir-ty/src/inhabitedness.rs
@@ -7,7 +7,7 @@ use chalk_ir::{
 };
 use hir_def::{
     attr::Attrs, data::adt::VariantData, visibility::Visibility, AdtId, EnumVariantId, HasModule,
-    Lookup, ModuleId, VariantId,
+    ModuleId, VariantId,
 };
 use rustc_hash::FxHashSet;
 
@@ -30,17 +30,15 @@ pub(crate) fn is_enum_variant_uninhabited_from(
     target_mod: ModuleId,
     db: &dyn HirDatabase,
 ) -> bool {
-    let enum_data = db.enum_data(variant.parent);
-    let vars_attrs = db.variants_attrs(variant.parent);
-    let is_local = variant.parent.lookup(db.upcast()).container.krate() == target_mod.krate();
+    let is_local = variant.module(db.upcast()).krate() == target_mod.krate();
 
     let mut uninhabited_from =
         UninhabitedFrom { target_mod, db, max_depth: 500, recursive_ty: FxHashSet::default() };
     let inhabitedness = uninhabited_from.visit_variant(
         variant.into(),
-        &enum_data.variants[variant.local_id].variant_data,
+        &db.enum_variant_data(variant).variant_data,
         subst,
-        &vars_attrs[variant.local_id],
+        &db.attrs(variant.into()),
         is_local,
     );
     inhabitedness == BREAK_VISIBLY_UNINHABITED
@@ -117,15 +115,14 @@ impl UninhabitedFrom<'_> {
                 self.visit_variant(s.into(), &struct_data.variant_data, subst, &attrs, is_local)
             }
             AdtId::EnumId(e) => {
-                let vars_attrs = self.db.variants_attrs(e);
                 let enum_data = self.db.enum_data(e);
 
-                for (local_id, enum_var) in enum_data.variants.iter() {
+                for &(variant, _) in enum_data.variants.iter() {
                     let variant_inhabitedness = self.visit_variant(
-                        EnumVariantId { parent: e, local_id }.into(),
-                        &enum_var.variant_data,
+                        variant.into(),
+                        &self.db.enum_variant_data(variant).variant_data,
                         subst,
-                        &vars_attrs[local_id],
+                        &self.db.attrs(variant.into()),
                         is_local,
                     );
                     match variant_inhabitedness {
diff --git a/crates/hir-ty/src/layout.rs b/crates/hir-ty/src/layout.rs
index 875906f9abd..5c7decb6892 100644
--- a/crates/hir-ty/src/layout.rs
+++ b/crates/hir-ty/src/layout.rs
@@ -9,7 +9,7 @@ use hir_def::{
         Abi, FieldsShape, Integer, LayoutCalculator, LayoutS, Primitive, ReprOptions, Scalar, Size,
         StructKind, TargetDataLayout, WrappingRange,
     },
-    LocalEnumVariantId, LocalFieldId, StructId,
+    LocalFieldId, StructId,
 };
 use la_arena::{Idx, RawIdx};
 use rustc_abi::AddressSpace;
@@ -32,15 +32,15 @@ mod adt;
 mod target;
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub struct RustcEnumVariantIdx(pub LocalEnumVariantId);
+pub struct RustcEnumVariantIdx(pub usize);
 
 impl rustc_index::Idx for RustcEnumVariantIdx {
     fn new(idx: usize) -> Self {
-        RustcEnumVariantIdx(Idx::from_raw(RawIdx::from(idx as u32)))
+        RustcEnumVariantIdx(idx)
     }
 
     fn index(self) -> usize {
-        u32::from(self.0.into_raw()) as usize
+        self.0
     }
 }
 
diff --git a/crates/hir-ty/src/layout/adt.rs b/crates/hir-ty/src/layout/adt.rs
index 8a7715ce872..9fcc251356f 100644
--- a/crates/hir-ty/src/layout/adt.rs
+++ b/crates/hir-ty/src/layout/adt.rs
@@ -6,9 +6,8 @@ use base_db::salsa::Cycle;
 use hir_def::{
     data::adt::VariantData,
     layout::{Integer, LayoutCalculator, ReprOptions, TargetDataLayout},
-    AdtId, EnumVariantId, LocalEnumVariantId, VariantId,
+    AdtId, VariantId,
 };
-use la_arena::RawIdx;
 use rustc_index::IndexVec;
 use smallvec::SmallVec;
 use triomphe::Arc;
@@ -22,8 +21,8 @@ use crate::{
 
 use super::LayoutCx;
 
-pub(crate) const fn struct_variant_idx() -> RustcEnumVariantIdx {
-    RustcEnumVariantIdx(LocalEnumVariantId::from_raw(RawIdx::from_u32(0)))
+pub(crate) fn struct_variant_idx() -> RustcEnumVariantIdx {
+    RustcEnumVariantIdx(0)
 }
 
 pub fn layout_of_adt_query(
@@ -62,12 +61,7 @@ pub fn layout_of_adt_query(
             let r = data
                 .variants
                 .iter()
-                .map(|(idx, v)| {
-                    handle_variant(
-                        EnumVariantId { parent: e, local_id: idx }.into(),
-                        &v.variant_data,
-                    )
-                })
+                .map(|&(v, _)| handle_variant(v.into(), &db.enum_variant_data(v).variant_data))
                 .collect::<Result<SmallVec<_>, _>>()?;
             (r, data.repr.unwrap_or_default())
         }
@@ -89,8 +83,7 @@ pub fn layout_of_adt_query(
             |min, max| repr_discr(&dl, &repr, min, max).unwrap_or((Integer::I8, false)),
             variants.iter_enumerated().filter_map(|(id, _)| {
                 let AdtId::EnumId(e) = def else { return None };
-                let d =
-                    db.const_eval_discriminant(EnumVariantId { parent: e, local_id: id.0 }).ok()?;
+                let d = db.const_eval_discriminant(db.enum_data(e).variants[id.0].0).ok()?;
                 Some((id, d))
             }),
             // FIXME: The current code for niche-filling relies on variant indices
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index e371e427615..f66b584e3b5 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -762,7 +762,7 @@ impl<'a> TyLoweringContext<'a> {
                     Some(segment) if segment.args_and_bindings.is_some() => Some(segment),
                     _ => last,
                 };
-                (segment, Some(var.parent.into()))
+                (segment, Some(var.lookup(self.db.upcast()).parent.into()))
             }
         };
         if let Some(segment) = segment {
@@ -1375,11 +1375,13 @@ pub(crate) fn field_types_query(
     let (resolver, def): (_, GenericDefId) = match variant_id {
         VariantId::StructId(it) => (it.resolver(db.upcast()), it.into()),
         VariantId::UnionId(it) => (it.resolver(db.upcast()), it.into()),
-        VariantId::EnumVariantId(it) => (it.parent.resolver(db.upcast()), it.parent.into()),
+        VariantId::EnumVariantId(it) => {
+            (it.resolver(db.upcast()), it.lookup(db.upcast()).parent.into())
+        }
     };
     let generics = generics(db.upcast(), def);
     let mut res = ArenaMap::default();
-    let ctx = TyLoweringContext::new(db, &resolver, GenericDefId::from(variant_id.adt_id()).into())
+    let ctx = TyLoweringContext::new(db, &resolver, def.into())
         .with_type_param_mode(ParamLoweringMode::Variable);
     for (field_id, field_data) in var_data.fields().iter() {
         res.insert(field_id, make_binders(db, &generics, ctx.lower_ty(&field_data.type_ref)));
@@ -1727,44 +1729,50 @@ fn fn_sig_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> PolyFnS
 /// Build the type of a tuple struct constructor.
 fn type_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> Binders<Ty> {
     let struct_data = db.struct_data(def);
-    if let StructKind::Unit = struct_data.variant_data.kind() {
-        return type_for_adt(db, def.into());
+    match struct_data.variant_data.kind() {
+        StructKind::Record => unreachable!("callers check for valueness of variant"),
+        StructKind::Unit => return type_for_adt(db, def.into()),
+        StructKind::Tuple => {
+            let generics = generics(db.upcast(), AdtId::from(def).into());
+            let substs = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
+            make_binders(
+                db,
+                &generics,
+                TyKind::FnDef(CallableDefId::StructId(def).to_chalk(db), substs).intern(Interner),
+            )
+        }
     }
-    let generics = generics(db.upcast(), AdtId::from(def).into());
-    let substs = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
-    make_binders(
-        db,
-        &generics,
-        TyKind::FnDef(CallableDefId::StructId(def).to_chalk(db), substs).intern(Interner),
-    )
 }
 
 fn fn_sig_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId) -> PolyFnSig {
-    let enum_data = db.enum_data(def.parent);
-    let var_data = &enum_data.variants[def.local_id];
+    let var_data = db.enum_variant_data(def);
     let fields = var_data.variant_data.fields();
-    let resolver = def.parent.resolver(db.upcast());
+    let resolver = def.resolver(db.upcast());
     let ctx = TyLoweringContext::new(db, &resolver, DefWithBodyId::VariantId(def).into())
         .with_type_param_mode(ParamLoweringMode::Variable);
     let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref)).collect::<Vec<_>>();
-    let (ret, binders) = type_for_adt(db, def.parent.into()).into_value_and_skipped_binders();
+    let (ret, binders) =
+        type_for_adt(db, def.lookup(db.upcast()).parent.into()).into_value_and_skipped_binders();
     Binders::new(binders, CallableSig::from_params_and_return(params, ret, false, Safety::Safe))
 }
 
 /// Build the type of a tuple enum variant constructor.
 fn type_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId) -> Binders<Ty> {
-    let enum_data = db.enum_data(def.parent);
-    let var_data = &enum_data.variants[def.local_id].variant_data;
-    if let StructKind::Unit = var_data.kind() {
-        return type_for_adt(db, def.parent.into());
+    let e = def.lookup(db.upcast()).parent;
+    match db.enum_variant_data(def).variant_data.kind() {
+        StructKind::Record => unreachable!("callers check for valueness of variant"),
+        StructKind::Unit => return type_for_adt(db, e.into()),
+        StructKind::Tuple => {
+            let generics = generics(db.upcast(), e.into());
+            let substs = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
+            make_binders(
+                db,
+                &generics,
+                TyKind::FnDef(CallableDefId::EnumVariantId(def).to_chalk(db), substs)
+                    .intern(Interner),
+            )
+        }
     }
-    let generics = generics(db.upcast(), def.parent.into());
-    let substs = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
-    make_binders(
-        db,
-        &generics,
-        TyKind::FnDef(CallableDefId::EnumVariantId(def).to_chalk(db), substs).intern(Interner),
-    )
 }
 
 fn type_for_adt(db: &dyn HirDatabase, adt: AdtId) -> Binders<Ty> {
@@ -1812,7 +1820,7 @@ impl CallableDefId {
         match self {
             CallableDefId::FunctionId(f) => f.lookup(db).module(db),
             CallableDefId::StructId(s) => s.lookup(db).container,
-            CallableDefId::EnumVariantId(e) => e.parent.lookup(db).container,
+            CallableDefId::EnumVariantId(e) => e.module(db),
         }
         .krate()
     }
@@ -1893,12 +1901,8 @@ pub(crate) fn value_ty_query(db: &dyn HirDatabase, def: ValueTyDefId) -> Binders
 }
 
 pub(crate) fn impl_self_ty_query(db: &dyn HirDatabase, impl_id: ImplId) -> Binders<Ty> {
-    let impl_loc = impl_id.lookup(db.upcast());
     let impl_data = db.impl_data(impl_id);
     let resolver = impl_id.resolver(db.upcast());
-    let _cx = stdx::panic_context::enter(format!(
-        "impl_self_ty_query({impl_id:?} -> {impl_loc:?} -> {impl_data:?})"
-    ));
     let generics = generics(db.upcast(), impl_id.into());
     let ctx = TyLoweringContext::new(db, &resolver, impl_id.into())
         .with_type_param_mode(ParamLoweringMode::Variable);
@@ -1930,12 +1934,8 @@ pub(crate) fn impl_self_ty_recover(
 }
 
 pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option<Binders<TraitRef>> {
-    let impl_loc = impl_id.lookup(db.upcast());
     let impl_data = db.impl_data(impl_id);
     let resolver = impl_id.resolver(db.upcast());
-    let _cx = stdx::panic_context::enter(format!(
-        "impl_trait_query({impl_id:?} -> {impl_loc:?} -> {impl_data:?})"
-    ));
     let ctx = TyLoweringContext::new(db, &resolver, impl_id.into())
         .with_type_param_mode(ParamLoweringMode::Variable);
     let (self_ty, binders) = db.impl_self_ty(impl_id).into_value_and_skipped_binders();
diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs
index 482d61f6959..551446962d1 100644
--- a/crates/hir-ty/src/mir/eval.rs
+++ b/crates/hir-ty/src/mir/eval.rs
@@ -752,7 +752,7 @@ impl Evaluator<'_> {
                         Variants::Multiple { variants, .. } => {
                             &variants[match f.parent {
                                 hir_def::VariantId::EnumVariantId(it) => {
-                                    RustcEnumVariantIdx(it.local_id)
+                                    RustcEnumVariantIdx(it.lookup(self.db.upcast()).index as usize)
                                 }
                                 _ => {
                                     return Err(MirEvalError::TypeError(
@@ -1412,22 +1412,12 @@ impl Evaluator<'_> {
 
     fn compute_discriminant(&self, ty: Ty, bytes: &[u8]) -> Result<i128> {
         let layout = self.layout(&ty)?;
-        let enum_id = 'b: {
-            match ty.kind(Interner) {
-                TyKind::Adt(e, _) => match e.0 {
-                    AdtId::EnumId(e) => break 'b e,
-                    _ => (),
-                },
-                _ => (),
-            }
+        let &TyKind::Adt(chalk_ir::AdtId(AdtId::EnumId(e)), _) = ty.kind(Interner) else {
             return Ok(0);
         };
         match &layout.variants {
             Variants::Single { index } => {
-                let r = self.const_eval_discriminant(EnumVariantId {
-                    parent: enum_id,
-                    local_id: index.0,
-                })?;
+                let r = self.const_eval_discriminant(self.db.enum_data(e).variants[index.0].0)?;
                 Ok(r)
             }
             Variants::Multiple { tag, tag_encoding, variants, .. } => {
@@ -1446,17 +1436,15 @@ impl Evaluator<'_> {
                         let candidate_tag = i128::from_le_bytes(pad16(tag, false))
                             .wrapping_sub(*niche_start as i128)
                             as usize;
-                        let variant = variants
+                        let idx = variants
                             .iter_enumerated()
                             .map(|(it, _)| it)
                             .filter(|it| it != untagged_variant)
                             .nth(candidate_tag)
                             .unwrap_or(*untagged_variant)
                             .0;
-                        let result = self.const_eval_discriminant(EnumVariantId {
-                            parent: enum_id,
-                            local_id: variant,
-                        })?;
+                        let result =
+                            self.const_eval_discriminant(self.db.enum_data(e).variants[idx].0)?;
                         Ok(result)
                     }
                 }
@@ -1579,14 +1567,16 @@ impl Evaluator<'_> {
         subst: Substitution,
         locals: &Locals,
     ) -> Result<(usize, Arc<Layout>, Option<(usize, usize, i128)>)> {
-        let adt = it.adt_id();
+        let adt = it.adt_id(self.db.upcast());
         if let DefWithBodyId::VariantId(f) = locals.body.owner {
             if let VariantId::EnumVariantId(it) = it {
-                if AdtId::from(f.parent) == adt {
-                    // Computing the exact size of enums require resolving the enum discriminants. In order to prevent loops (and
-                    // infinite sized type errors) we use a dummy layout
-                    let i = self.const_eval_discriminant(it)?;
-                    return Ok((16, self.layout(&TyBuilder::unit())?, Some((0, 16, i))));
+                if let AdtId::EnumId(e) = adt {
+                    if f.lookup(self.db.upcast()).parent == e {
+                        // Computing the exact size of enums require resolving the enum discriminants. In order to prevent loops (and
+                        // infinite sized type errors) we use a dummy layout
+                        let i = self.const_eval_discriminant(it)?;
+                        return Ok((16, self.layout(&TyBuilder::unit())?, Some((0, 16, i))));
+                    }
                 }
             }
         }
@@ -1602,8 +1592,9 @@ impl Evaluator<'_> {
                     VariantId::EnumVariantId(it) => it,
                     _ => not_supported!("multi variant layout for non-enums"),
                 };
-                let rustc_enum_variant_idx = RustcEnumVariantIdx(enum_variant_id.local_id);
                 let mut discriminant = self.const_eval_discriminant(enum_variant_id)?;
+                let lookup = enum_variant_id.lookup(self.db.upcast());
+                let rustc_enum_variant_idx = RustcEnumVariantIdx(lookup.index as usize);
                 let variant_layout = variants[rustc_enum_variant_idx].clone();
                 let have_tag = match tag_encoding {
                     TagEncoding::Direct => true,
@@ -1847,8 +1838,8 @@ impl Evaluator<'_> {
                 .then(|| (layout.size.bytes_usize(), layout.align.abi.bytes() as usize)));
         }
         if let DefWithBodyId::VariantId(f) = locals.body.owner {
-            if let Some((adt, _)) = ty.as_adt() {
-                if AdtId::from(f.parent) == adt {
+            if let Some((AdtId::EnumId(e), _)) = ty.as_adt() {
+                if f.lookup(self.db.upcast()).parent == e {
                     // Computing the exact size of enums require resolving the enum discriminants. In order to prevent loops (and
                     // infinite sized type errors) we use a dummy size
                     return Ok(Some((16, 16)));
@@ -2019,10 +2010,8 @@ impl Evaluator<'_> {
                             bytes,
                             e,
                         ) {
-                            let data = &this.db.enum_data(e).variants[v].variant_data;
-                            let field_types = this
-                                .db
-                                .field_types(EnumVariantId { parent: e, local_id: v }.into());
+                            let data = &this.db.enum_variant_data(v).variant_data;
+                            let field_types = this.db.field_types(v.into());
                             for (f, _) in data.fields().iter() {
                                 let offset =
                                     l.fields.offset(u32::from(f.into_raw()) as usize).bytes_usize();
@@ -2093,14 +2082,13 @@ impl Evaluator<'_> {
                 }
                 AdtId::UnionId(_) => (),
                 AdtId::EnumId(e) => {
-                    if let Some((variant, layout)) = detect_variant_from_bytes(
+                    if let Some((ev, layout)) = detect_variant_from_bytes(
                         &layout,
                         self.db,
                         self.trait_env.clone(),
                         self.read_memory(addr, layout.size.bytes_usize())?,
                         e,
                     ) {
-                        let ev = EnumVariantId { parent: e, local_id: variant };
                         for (i, (_, ty)) in self.db.field_types(ev.into()).iter().enumerate() {
                             let offset = layout.fields.offset(i).bytes_usize();
                             let ty = ty.clone().substitute(Interner, subst);
@@ -2540,11 +2528,13 @@ impl Evaluator<'_> {
         match r {
             Ok(r) => Ok(r),
             Err(e) => {
-                let data = self.db.enum_data(variant.parent);
+                let db = self.db.upcast();
+                let loc = variant.lookup(db);
+                let enum_loc = loc.parent.lookup(db);
                 let name = format!(
                     "{}::{}",
-                    data.name.display(self.db.upcast()),
-                    data.variants[variant.local_id].name.display(self.db.upcast())
+                    enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db.upcast()),
+                    loc.id.item_tree(db)[loc.id.value].name.display(db.upcast()),
                 );
                 Err(MirEvalError::ConstEvalError(name, Box::new(e)))
             }
diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs
index c02c5ef8767..749ca43fba7 100644
--- a/crates/hir-ty/src/mir/lower.rs
+++ b/crates/hir-ty/src/mir/lower.rs
@@ -69,6 +69,7 @@ struct MirLowerCtx<'a> {
     drop_scopes: Vec<DropScope>,
 }
 
+// FIXME: Make this smaller, its stored in database queries
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub enum MirLowerError {
     ConstEvalError(Box<str>, Box<ConstEvalError>),
@@ -456,9 +457,8 @@ impl<'ctx> MirLowerCtx<'ctx> {
                         Ok(Some(current))
                     }
                     ValueNs::EnumVariantId(variant_id) => {
-                        let variant_data =
-                            &self.db.enum_data(variant_id.parent).variants[variant_id.local_id];
-                        if variant_data.variant_data.kind() == StructKind::Unit {
+                        let variant_data = &self.db.enum_variant_data(variant_id).variant_data;
+                        if variant_data.kind() == StructKind::Unit {
                             let ty = self.infer.type_of_expr[expr_id].clone();
                             current = self.lower_enum_variant(
                                 variant_id,
@@ -1874,11 +1874,13 @@ impl<'ctx> MirLowerCtx<'ctx> {
         match r {
             Ok(r) => Ok(r),
             Err(e) => {
-                let data = self.db.enum_data(variant.parent);
+                let db = self.db.upcast();
+                let loc = variant.lookup(db);
+                let enum_loc = loc.parent.lookup(db);
                 let name = format!(
                     "{}::{}",
-                    data.name.display(self.db.upcast()),
-                    data.variants[variant.local_id].name.display(self.db.upcast())
+                    enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db.upcast()),
+                    loc.id.item_tree(db)[loc.id.value].name.display(db.upcast()),
                 );
                 Err(MirLowerError::ConstEvalError(name.into(), Box::new(e)))
             }
@@ -2104,7 +2106,7 @@ pub fn mir_body_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Result<Arc<Mi
             .display(db.upcast())
             .to_string(),
         DefWithBodyId::VariantId(it) => {
-            db.enum_data(it.parent).variants[it.local_id].name.display(db.upcast()).to_string()
+            db.enum_variant_data(it).name.display(db.upcast()).to_string()
         }
         DefWithBodyId::InTypeConstId(it) => format!("in type const {it:?}"),
     });
diff --git a/crates/hir-ty/src/mir/lower/pattern_matching.rs b/crates/hir-ty/src/mir/lower/pattern_matching.rs
index 98c2e7c63bc..bbb513b24cb 100644
--- a/crates/hir-ty/src/mir/lower/pattern_matching.rs
+++ b/crates/hir-ty/src/mir/lower/pattern_matching.rs
@@ -524,22 +524,9 @@ impl MirLowerCtx<'_> {
                     );
                     current = next;
                 }
-                let enum_data = self.db.enum_data(v.parent);
                 self.pattern_matching_variant_fields(
                     shape,
-                    &enum_data.variants[v.local_id].variant_data,
-                    variant,
-                    current,
-                    current_else,
-                    &cond_place,
-                    mode,
-                )?
-            }
-            VariantId::StructId(s) => {
-                let struct_data = self.db.struct_data(s);
-                self.pattern_matching_variant_fields(
-                    shape,
-                    &struct_data.variant_data,
+                    &self.db.enum_variant_data(v).variant_data,
                     variant,
                     current,
                     current_else,
@@ -547,6 +534,15 @@ impl MirLowerCtx<'_> {
                     mode,
                 )?
             }
+            VariantId::StructId(s) => self.pattern_matching_variant_fields(
+                shape,
+                &self.db.struct_data(s).variant_data,
+                variant,
+                current,
+                current_else,
+                &cond_place,
+                mode,
+            )?,
             VariantId::UnionId(_) => {
                 return Err(MirLowerError::TypeError("pattern matching on union"))
             }
diff --git a/crates/hir-ty/src/mir/pretty.rs b/crates/hir-ty/src/mir/pretty.rs
index 366c2f662b5..65fb5884825 100644
--- a/crates/hir-ty/src/mir/pretty.rs
+++ b/crates/hir-ty/src/mir/pretty.rs
@@ -7,7 +7,7 @@ use std::{
 
 use either::Either;
 use hir_def::{body::Body, hir::BindingId};
-use hir_expand::name::Name;
+use hir_expand::{name::Name, Lookup};
 use la_arena::ArenaMap;
 
 use crate::{
@@ -58,8 +58,14 @@ impl MirBody {
                 );
             }
             hir_def::DefWithBodyId::VariantId(id) => {
-                let data = db.enum_data(id.parent);
-                w!(this, "enum {} = ", data.name.display(db.upcast()));
+                let loc = id.lookup(db.upcast());
+                let enum_loc = loc.parent.lookup(db.upcast());
+                w!(
+                    this,
+                    "enum {}::{} = ",
+                    enum_loc.id.item_tree(db.upcast())[enum_loc.id.value].name.display(db.upcast()),
+                    loc.id.item_tree(db.upcast())[loc.id.value].name.display(db.upcast()),
+                )
             }
             hir_def::DefWithBodyId::InTypeConstId(id) => {
                 w!(this, "in type const {id:?} = ");
@@ -306,8 +312,7 @@ impl<'a> MirPrettyCtx<'a> {
                         hir_def::VariantId::EnumVariantId(e) => {
                             w!(this, "(");
                             f(this, local, head);
-                            let variant_name =
-                                &this.db.enum_data(e.parent).variants[e.local_id].name;
+                            let variant_name = &this.db.enum_variant_data(e).name;
                             w!(
                                 this,
                                 " as {}).{}",
diff --git a/crates/hir-ty/src/tests.rs b/crates/hir-ty/src/tests.rs
index c8cc61cc21b..671fd9ec3a4 100644
--- a/crates/hir-ty/src/tests.rs
+++ b/crates/hir-ty/src/tests.rs
@@ -16,7 +16,7 @@ use base_db::{FileRange, SourceDatabaseExt};
 use expect_test::Expect;
 use hir_def::{
     body::{Body, BodySourceMap, SyntheticSyntax},
-    db::{DefDatabase, InternDatabase},
+    db::DefDatabase,
     hir::{ExprId, Pat, PatId},
     item_scope::ItemScope,
     nameres::DefMap,
@@ -145,7 +145,7 @@ fn check_impl(ra_fixture: &str, allow_none: bool, only_types: bool, display_sour
             loc.source(&db).value.syntax().text_range().start()
         }
         DefWithBodyId::VariantId(it) => {
-            let loc = db.lookup_intern_enum(it.parent);
+            let loc = it.lookup(&db);
             loc.source(&db).value.syntax().text_range().start()
         }
         DefWithBodyId::InTypeConstId(it) => it.source(&db).syntax().text_range().start(),
@@ -383,7 +383,7 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
             loc.source(&db).value.syntax().text_range().start()
         }
         DefWithBodyId::VariantId(it) => {
-            let loc = db.lookup_intern_enum(it.parent);
+            let loc = it.lookup(&db);
             loc.source(&db).value.syntax().text_range().start()
         }
         DefWithBodyId::InTypeConstId(it) => it.source(&db).syntax().text_range().start(),
@@ -453,16 +453,12 @@ fn visit_module(
                     visit_body(db, &body, cb);
                 }
                 ModuleDefId::AdtId(hir_def::AdtId::EnumId(it)) => {
-                    db.enum_data(it)
-                        .variants
-                        .iter()
-                        .map(|(id, _)| hir_def::EnumVariantId { parent: it, local_id: id })
-                        .for_each(|it| {
-                            let def = it.into();
-                            cb(def);
-                            let body = db.body(def);
-                            visit_body(db, &body, cb);
-                        });
+                    db.enum_data(it).variants.iter().for_each(|&(it, _)| {
+                        let def = it.into();
+                        cb(def);
+                        let body = db.body(def);
+                        visit_body(db, &body, cb);
+                    });
                 }
                 ModuleDefId::TraitId(it) => {
                     let trait_data = db.trait_data(it);
diff --git a/crates/hir-ty/src/tls.rs b/crates/hir-ty/src/tls.rs
index 83814ed0ec1..db5fa320577 100644
--- a/crates/hir-ty/src/tls.rs
+++ b/crates/hir-ty/src/tls.rs
@@ -107,10 +107,7 @@ impl DebugContext<'_> {
         let name = match def {
             CallableDefId::FunctionId(ff) => self.0.function_data(ff).name.clone(),
             CallableDefId::StructId(s) => self.0.struct_data(s).name.clone(),
-            CallableDefId::EnumVariantId(e) => {
-                let enum_data = self.0.enum_data(e.parent);
-                enum_data.variants[e.local_id].name.clone()
-            }
+            CallableDefId::EnumVariantId(e) => self.0.enum_variant_data(e).name.clone(),
         };
         match def {
             CallableDefId::FunctionId(_) => write!(fmt, "{{fn {}}}", name.display(self.0.upcast())),
diff --git a/crates/hir-ty/src/utils.rs b/crates/hir-ty/src/utils.rs
index 75b8b9afa70..e80eab87009 100644
--- a/crates/hir-ty/src/utils.rs
+++ b/crates/hir-ty/src/utils.rs
@@ -19,9 +19,8 @@ use hir_def::{
     lang_item::LangItem,
     resolver::{HasResolver, TypeNs},
     type_ref::{TraitBoundModifier, TypeRef},
-    ConstParamId, EnumId, EnumVariantId, FunctionId, GenericDefId, ItemContainerId,
-    LocalEnumVariantId, Lookup, OpaqueInternableThing, TraitId, TypeAliasId, TypeOrConstParamId,
-    TypeParamId,
+    ConstParamId, EnumId, EnumVariantId, FunctionId, GenericDefId, ItemContainerId, Lookup,
+    OpaqueInternableThing, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId,
 };
 use hir_expand::name::Name;
 use intern::Interned;
@@ -355,7 +354,7 @@ fn parent_generic_def(db: &dyn DefDatabase, def: GenericDefId) -> Option<Generic
         GenericDefId::FunctionId(it) => it.lookup(db).container,
         GenericDefId::TypeAliasId(it) => it.lookup(db).container,
         GenericDefId::ConstId(it) => it.lookup(db).container,
-        GenericDefId::EnumVariantId(it) => return Some(it.parent.into()),
+        GenericDefId::EnumVariantId(it) => return Some(it.lookup(db).parent.into()),
         GenericDefId::AdtId(_)
         | GenericDefId::TraitId(_)
         | GenericDefId::ImplId(_)
@@ -435,10 +434,12 @@ pub(crate) fn detect_variant_from_bytes<'a>(
     trait_env: Arc<TraitEnvironment>,
     b: &[u8],
     e: EnumId,
-) -> Option<(LocalEnumVariantId, &'a Layout)> {
+) -> Option<(EnumVariantId, &'a Layout)> {
     let krate = trait_env.krate;
     let (var_id, var_layout) = match &layout.variants {
-        hir_def::layout::Variants::Single { index } => (index.0, &*layout),
+        hir_def::layout::Variants::Single { index } => {
+            (db.enum_data(e).variants[index.0].0, &*layout)
+        }
         hir_def::layout::Variants::Multiple { tag, tag_encoding, variants, .. } => {
             let target_data_layout = db.target_data_layout(krate)?;
             let size = tag.size(&*target_data_layout).bytes_usize();
@@ -446,11 +447,12 @@ pub(crate) fn detect_variant_from_bytes<'a>(
             let tag = i128::from_le_bytes(pad16(&b[offset..offset + size], false));
             match tag_encoding {
                 TagEncoding::Direct => {
-                    let x = variants.iter_enumerated().find(|x| {
-                        db.const_eval_discriminant(EnumVariantId { parent: e, local_id: x.0 .0 })
-                            == Ok(tag)
-                    })?;
-                    (x.0 .0, x.1)
+                    let (var_idx, layout) =
+                        variants.iter_enumerated().find_map(|(var_idx, v)| {
+                            let def = db.enum_data(e).variants[var_idx.0].0;
+                            (db.const_eval_discriminant(def) == Ok(tag)).then_some((def, v))
+                        })?;
+                    (var_idx, layout)
                 }
                 TagEncoding::Niche { untagged_variant, niche_start, .. } => {
                     let candidate_tag = tag.wrapping_sub(*niche_start as i128) as usize;
@@ -460,7 +462,7 @@ pub(crate) fn detect_variant_from_bytes<'a>(
                         .filter(|x| x != untagged_variant)
                         .nth(candidate_tag)
                         .unwrap_or(*untagged_variant);
-                    (variant.0, &variants[variant])
+                    (db.enum_data(e).variants[variant.0].0, &variants[variant])
                 }
             }
         }
diff --git a/crates/hir/src/attrs.rs b/crates/hir/src/attrs.rs
index 5a21f41dca8..7b9f895bc73 100644
--- a/crates/hir/src/attrs.rs
+++ b/crates/hir/src/attrs.rs
@@ -115,7 +115,7 @@ fn resolve_doc_path_on_(
         AttrDefId::FieldId(it) => it.parent.resolver(db.upcast()),
         AttrDefId::AdtId(it) => it.resolver(db.upcast()),
         AttrDefId::FunctionId(it) => it.resolver(db.upcast()),
-        AttrDefId::EnumVariantId(it) => it.parent.resolver(db.upcast()),
+        AttrDefId::EnumVariantId(it) => it.resolver(db.upcast()),
         AttrDefId::StaticId(it) => it.resolver(db.upcast()),
         AttrDefId::ConstId(it) => it.resolver(db.upcast()),
         AttrDefId::TraitId(it) => it.resolver(db.upcast()),
diff --git a/crates/hir/src/db.rs b/crates/hir/src/db.rs
index 403a6c88ab0..a2492840cb7 100644
--- a/crates/hir/src/db.rs
+++ b/crates/hir/src/db.rs
@@ -6,8 +6,8 @@
 pub use hir_def::db::{
     AttrsQuery, BlockDefMapQuery, BlockItemTreeQueryQuery, BodyQuery, BodyWithSourceMapQuery,
     ConstDataQuery, ConstVisibilityQuery, CrateDefMapQueryQuery, CrateLangItemsQuery,
-    CrateSupportsNoStdQuery, DefDatabase, DefDatabaseStorage, EnumDataQuery,
-    EnumDataWithDiagnosticsQuery, ExprScopesQuery, ExternCrateDeclDataQuery,
+    CrateSupportsNoStdQuery, DefDatabase, DefDatabaseStorage, EnumDataQuery, EnumVariantDataQuery,
+    EnumVariantDataWithDiagnosticsQuery, ExprScopesQuery, ExternCrateDeclDataQuery,
     FieldVisibilitiesQuery, FieldsAttrsQuery, FieldsAttrsSourceMapQuery, FileItemTreeQuery,
     FunctionDataQuery, FunctionVisibilityQuery, GenericParamsQuery, ImplDataQuery,
     ImplDataWithDiagnosticsQuery, ImportMapQuery, InternAnonymousConstQuery, InternBlockQuery,
@@ -19,7 +19,7 @@ pub use hir_def::db::{
     MacroRulesDataQuery, ProcMacroDataQuery, StaticDataQuery, StructDataQuery,
     StructDataWithDiagnosticsQuery, TraitAliasDataQuery, TraitDataQuery,
     TraitDataWithDiagnosticsQuery, TypeAliasDataQuery, UnionDataQuery,
-    UnionDataWithDiagnosticsQuery, VariantsAttrsQuery, VariantsAttrsSourceMapQuery,
+    UnionDataWithDiagnosticsQuery,
 };
 pub use hir_expand::db::{
     AstIdMapQuery, DeclMacroExpanderQuery, ExpandDatabase, ExpandDatabaseStorage,
diff --git a/crates/hir/src/from_id.rs b/crates/hir/src/from_id.rs
index fc4bbffdb83..887227bf4d0 100644
--- a/crates/hir/src/from_id.rs
+++ b/crates/hir/src/from_id.rs
@@ -93,13 +93,13 @@ impl From<GenericParam> for GenericParamId {
 
 impl From<EnumVariantId> for Variant {
     fn from(id: EnumVariantId) -> Self {
-        Variant { parent: id.parent.into(), id: id.local_id }
+        Variant { id }
     }
 }
 
 impl From<Variant> for EnumVariantId {
     fn from(def: Variant) -> Self {
-        EnumVariantId { parent: def.parent.id, local_id: def.id }
+        def.id
     }
 }
 
diff --git a/crates/hir/src/has_source.rs b/crates/hir/src/has_source.rs
index 31cf8ba3364..d10884517f9 100644
--- a/crates/hir/src/has_source.rs
+++ b/crates/hir/src/has_source.rs
@@ -116,7 +116,7 @@ impl HasSource for Enum {
 impl HasSource for Variant {
     type Ast = ast::Variant;
     fn source(self, db: &dyn HirDatabase) -> Option<InFile<ast::Variant>> {
-        Some(self.parent.id.child_source(db.upcast()).map(|map| map[self.id].clone()))
+        Some(self.id.lookup(db.upcast()).source(db.upcast()))
     }
 }
 impl HasSource for Function {
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index c92939362ca..45aa3a05304 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -44,7 +44,7 @@ use hir_def::{
     data::adt::VariantData,
     generics::{LifetimeParamData, TypeOrConstParamData, TypeParamProvenance},
     hir::{BindingAnnotation, BindingId, ExprOrPatId, LabelId, Pat},
-    item_tree::ItemTreeNode,
+    item_tree::ItemTreeModItemNode,
     lang_item::LangItemTarget,
     layout::{self, ReprOptions, TargetDataLayout},
     nameres::{self, diagnostics::DefDiagnostic},
@@ -54,9 +54,9 @@ use hir_def::{
     src::HasSource as _,
     AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, CrateRootModuleId, DefWithBodyId,
     EnumId, EnumVariantId, ExternCrateId, FunctionId, GenericDefId, GenericParamId, HasModule,
-    ImplId, InTypeConstId, ItemContainerId, LifetimeParamId, LocalEnumVariantId, LocalFieldId,
-    Lookup, MacroExpander, MacroId, ModuleId, StaticId, StructId, TraitAliasId, TraitId, TupleId,
-    TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId,
+    ImplId, InTypeConstId, ItemContainerId, LifetimeParamId, LocalFieldId, Lookup, MacroExpander,
+    MacroId, ModuleId, StaticId, StructId, TraitAliasId, TraitId, TupleId, TypeAliasId,
+    TypeOrConstParamId, TypeParamId, UnionId,
 };
 use hir_expand::{attrs::collect_attrs, name::name, proc_macro::ProcMacroKind, MacroCallKind};
 use hir_ty::{
@@ -375,9 +375,7 @@ impl ModuleDef {
             ModuleDef::Module(it) => it.id.into(),
             ModuleDef::Const(it) => it.id.into(),
             ModuleDef::Static(it) => it.id.into(),
-            ModuleDef::Variant(it) => {
-                EnumVariantId { parent: it.parent.into(), local_id: it.id }.into()
-            }
+            ModuleDef::Variant(it) => it.id.into(),
             ModuleDef::BuiltinType(_) | ModuleDef::Macro(_) => return Vec::new(),
         };
 
@@ -586,10 +584,9 @@ impl Module {
                         Adt::Enum(e) => {
                             for v in e.variants(db) {
                                 acc.extend(ModuleDef::Variant(v).diagnostics(db));
-                            }
-
-                            for diag in db.enum_data_with_diagnostics(e.id).1.iter() {
-                                emit_def_diagnostic(db, acc, diag);
+                                for diag in db.enum_variant_data_with_diagnostics(v.id).1.iter() {
+                                    emit_def_diagnostic(db, acc, diag);
+                                }
                             }
                         }
                     }
@@ -1084,7 +1081,7 @@ impl Field {
         let generic_def_id: GenericDefId = match self.parent {
             VariantDef::Struct(it) => it.id.into(),
             VariantDef::Union(it) => it.id.into(),
-            VariantDef::Variant(it) => it.parent.id.into(),
+            VariantDef::Variant(it) => it.id.into(),
         };
         let substs = TyBuilder::placeholder_subst(db, generic_def_id);
         let ty = db.field_types(var_id)[self.id].clone().substitute(Interner, &substs);
@@ -1224,7 +1221,7 @@ impl Enum {
     }
 
     pub fn variants(self, db: &dyn HirDatabase) -> Vec<Variant> {
-        db.enum_data(self.id).variants.iter().map(|(id, _)| Variant { parent: self, id }).collect()
+        db.enum_data(self.id).variants.iter().map(|&(id, _)| Variant { id }).collect()
     }
 
     pub fn repr(self, db: &dyn HirDatabase) -> Option<ReprOptions> {
@@ -1292,25 +1289,24 @@ impl From<&Variant> for DefWithBodyId {
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct Variant {
-    pub(crate) parent: Enum,
-    pub(crate) id: LocalEnumVariantId,
+    pub(crate) id: EnumVariantId,
 }
 
 impl Variant {
     pub fn module(self, db: &dyn HirDatabase) -> Module {
-        self.parent.module(db)
+        Module { id: self.id.module(db.upcast()) }
     }
 
-    pub fn parent_enum(self, _db: &dyn HirDatabase) -> Enum {
-        self.parent
+    pub fn parent_enum(self, db: &dyn HirDatabase) -> Enum {
+        self.id.lookup(db.upcast()).parent.into()
     }
 
     pub fn constructor_ty(self, db: &dyn HirDatabase) -> Type {
-        Type::from_value_def(db, EnumVariantId { parent: self.parent.id, local_id: self.id })
+        Type::from_value_def(db, self.id)
     }
 
     pub fn name(self, db: &dyn HirDatabase) -> Name {
-        db.enum_data(self.parent.id).variants[self.id].name.clone()
+        db.enum_variant_data(self.id).name.clone()
     }
 
     pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> {
@@ -1326,7 +1322,7 @@ impl Variant {
     }
 
     pub(crate) fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> {
-        db.enum_data(self.parent.id).variants[self.id].variant_data.clone()
+        db.enum_variant_data(self.id).variant_data.clone()
     }
 
     pub fn value(self, db: &dyn HirDatabase) -> Option<ast::Expr> {
@@ -1342,7 +1338,11 @@ impl Variant {
         let parent_layout = parent_enum.layout(db)?;
         Ok(match &parent_layout.0.variants {
             layout::Variants::Multiple { variants, .. } => Layout(
-                Arc::new(variants[RustcEnumVariantIdx(self.id)].clone()),
+                {
+                    let lookup = self.id.lookup(db.upcast());
+                    let rustc_enum_variant_idx = RustcEnumVariantIdx(lookup.index as usize);
+                    Arc::new(variants[rustc_enum_variant_idx].clone())
+                },
                 db.target_data_layout(parent_enum.krate(db).into()).unwrap(),
             ),
             _ => parent_layout,
@@ -1547,7 +1547,7 @@ impl DefWithBody {
             DefWithBody::Function(it) => it.ret_type(db),
             DefWithBody::Static(it) => it.ty(db),
             DefWithBody::Const(it) => it.ty(db),
-            DefWithBody::Variant(it) => it.parent.variant_body_ty(db),
+            DefWithBody::Variant(it) => it.parent_enum(db).variant_body_ty(db),
             DefWithBody::InTypeConst(it) => Type::new_with_resolver_inner(
                 db,
                 &DefWithBodyId::from(it.id).resolver(db.upcast()),
@@ -2828,7 +2828,7 @@ where
     ID: Lookup<Database<'db> = dyn DefDatabase + 'db, Data = AssocItemLoc<AST>>,
     DEF: From<ID>,
     CTOR: FnOnce(DEF) -> AssocItem,
-    AST: ItemTreeNode,
+    AST: ItemTreeModItemNode,
 {
     match id.lookup(db.upcast()).container {
         ItemContainerId::TraitId(_) | ItemContainerId::ImplId(_) => Some(ctor(DEF::from(id))),
diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs
index df8c1e904fe..cb04f98911e 100644
--- a/crates/hir/src/semantics/source_to_def.rs
+++ b/crates/hir/src/semantics/source_to_def.rs
@@ -201,7 +201,7 @@ impl SourceToDefCtx<'_, '_> {
         &mut self,
         src: InFile<ast::Variant>,
     ) -> Option<EnumVariantId> {
-        self.to_def(src, keys::VARIANT)
+        self.to_def(src, keys::ENUM_VARIANT)
     }
     pub(super) fn extern_crate_to_def(
         &mut self,
diff --git a/crates/hir/src/symbols.rs b/crates/hir/src/symbols.rs
index e1101dd8236..28ac5940e69 100644
--- a/crates/hir/src/symbols.rs
+++ b/crates/hir/src/symbols.rs
@@ -262,9 +262,7 @@ impl<'a> SymbolCollector<'a> {
             DefWithBodyId::FunctionId(id) => Some(self.db.function_data(id).name.to_smol_str()),
             DefWithBodyId::StaticId(id) => Some(self.db.static_data(id).name.to_smol_str()),
             DefWithBodyId::ConstId(id) => Some(self.db.const_data(id).name.as_ref()?.to_smol_str()),
-            DefWithBodyId::VariantId(id) => {
-                Some(self.db.enum_data(id.parent).variants[id.local_id].name.to_smol_str())
-            }
+            DefWithBodyId::VariantId(id) => Some(self.db.enum_variant_data(id).name.to_smol_str()),
             DefWithBodyId::InTypeConstId(_) => Some("in type const".into()),
         }
     }
diff --git a/crates/ide-db/src/apply_change.rs b/crates/ide-db/src/apply_change.rs
index 4f21f181d7c..3d973dfe10a 100644
--- a/crates/ide-db/src/apply_change.rs
+++ b/crates/ide-db/src/apply_change.rs
@@ -141,7 +141,8 @@ impl RootDatabase {
             hir::db::UnionDataQuery
             hir::db::UnionDataWithDiagnosticsQuery
             hir::db::EnumDataQuery
-            hir::db::EnumDataWithDiagnosticsQuery
+            hir::db::EnumVariantDataWithDiagnosticsQuery
+            hir::db::EnumVariantDataQuery
             hir::db::ImplDataQuery
             hir::db::ImplDataWithDiagnosticsQuery
             hir::db::TraitDataQuery
@@ -158,9 +159,7 @@ impl RootDatabase {
             hir::db::BodyQuery
             hir::db::ExprScopesQuery
             hir::db::GenericParamsQuery
-            hir::db::VariantsAttrsQuery
             hir::db::FieldsAttrsQuery
-            hir::db::VariantsAttrsSourceMapQuery
             hir::db::FieldsAttrsSourceMapQuery
             hir::db::AttrsQuery
             hir::db::CrateLangItemsQuery
diff --git a/crates/ide-db/src/lib.rs b/crates/ide-db/src/lib.rs
index ff26d862bfe..e1b6c13ba8e 100644
--- a/crates/ide-db/src/lib.rs
+++ b/crates/ide-db/src/lib.rs
@@ -222,7 +222,8 @@ impl RootDatabase {
             hir_db::UnionDataQuery
             hir_db::UnionDataWithDiagnosticsQuery
             hir_db::EnumDataQuery
-            hir_db::EnumDataWithDiagnosticsQuery
+            hir_db::EnumDataQuery
+            hir_db::EnumVariantDataWithDiagnosticsQuery
             hir_db::ImplDataQuery
             hir_db::ImplDataWithDiagnosticsQuery
             hir_db::TraitDataQuery
@@ -239,9 +240,7 @@ impl RootDatabase {
             hir_db::BodyQuery
             hir_db::ExprScopesQuery
             hir_db::GenericParamsQuery
-            hir_db::VariantsAttrsQuery
             hir_db::FieldsAttrsQuery
-            hir_db::VariantsAttrsSourceMapQuery
             hir_db::FieldsAttrsSourceMapQuery
             hir_db::AttrsQuery
             hir_db::CrateLangItemsQuery
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs
index 1c6157de559..19c2d3be16b 100644
--- a/crates/syntax/src/ast/node_ext.rs
+++ b/crates/syntax/src/ast/node_ext.rs
@@ -440,6 +440,12 @@ impl ast::Struct {
     }
 }
 
+impl ast::Union {
+    pub fn kind(&self) -> StructKind {
+        StructKind::from_node(self)
+    }
+}
+
 impl ast::RecordExprField {
     pub fn for_field_name(field_name: &ast::NameRef) -> Option<ast::RecordExprField> {
         let candidate = Self::for_name_ref(field_name)?;