Unnamed repository; edit this file 'description' to name the repository.
Merge pull request #19837 from ChayimFriedman2/stable-astid
Provide better incrementality when items are changed
Lukas Wirth 11 months ago
parent 2095af2 · parent 9a1063f · commit c15fc9a
-rw-r--r--.typos.toml1
-rw-r--r--crates/hir-def/src/attr.rs158
-rw-r--r--crates/hir-def/src/db.rs36
-rw-r--r--crates/hir-def/src/expr_store/expander.rs7
-rw-r--r--crates/hir-def/src/expr_store/lower.rs41
-rw-r--r--crates/hir-def/src/expr_store/pretty.rs76
-rw-r--r--crates/hir-def/src/item_tree.rs200
-rw-r--r--crates/hir-def/src/item_tree/lower.rs198
-rw-r--r--crates/hir-def/src/item_tree/pretty.rs102
-rw-r--r--crates/hir-def/src/item_tree/tests.rs99
-rw-r--r--crates/hir-def/src/lang_item.rs2
-rw-r--r--crates/hir-def/src/lib.rs187
-rw-r--r--crates/hir-def/src/macro_expansion_tests/mbe.rs22
-rw-r--r--crates/hir-def/src/macro_expansion_tests/proc_macros.rs6
-rw-r--r--crates/hir-def/src/nameres.rs2
-rw-r--r--crates/hir-def/src/nameres/assoc.rs212
-rw-r--r--crates/hir-def/src/nameres/collector.rs176
-rw-r--r--crates/hir-def/src/nameres/diagnostics.rs25
-rw-r--r--crates/hir-def/src/nameres/path_resolution.rs34
-rw-r--r--crates/hir-def/src/resolver.rs36
-rw-r--r--crates/hir-def/src/signatures.rs400
-rw-r--r--crates/hir-def/src/src.rs106
-rw-r--r--crates/hir-def/src/visibility.rs82
-rw-r--r--crates/hir-expand/src/builtin/quote.rs4
-rw-r--r--crates/hir-expand/src/db.rs1
-rw-r--r--crates/hir-expand/src/files.rs9
-rw-r--r--crates/hir-ty/src/chalk_db.rs2
-rw-r--r--crates/hir-ty/src/diagnostics/decl_check.rs4
-rw-r--r--crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs2
-rw-r--r--crates/hir-ty/src/drop.rs2
-rw-r--r--crates/hir-ty/src/inhabitedness.rs2
-rw-r--r--crates/hir-ty/src/layout/adt.rs2
-rw-r--r--crates/hir-ty/src/mir/eval.rs9
-rw-r--r--crates/hir-ty/src/mir/eval/shim.rs7
-rw-r--r--crates/hir-ty/src/mir/lower.rs9
-rw-r--r--crates/hir-ty/src/mir/pretty.rs13
-rw-r--r--crates/hir-ty/src/tests.rs2
-rw-r--r--crates/hir-ty/src/tests/incremental.rs3
-rw-r--r--crates/hir-ty/src/utils.rs4
-rw-r--r--crates/hir-ty/src/variance.rs2
-rw-r--r--crates/hir/src/lib.rs233
-rw-r--r--crates/hir/src/semantics/child_by_source.rs25
-rw-r--r--crates/mbe/src/tests.rs232
-rw-r--r--crates/proc-macro-api/src/legacy_protocol/msg.rs13
-rw-r--r--crates/proc-macro-api/src/process.rs14
-rw-r--r--crates/proc-macro-srv-cli/src/main_loop.rs7
-rw-r--r--crates/proc-macro-srv/src/dylib.rs15
-rw-r--r--crates/proc-macro-srv/src/lib.rs32
-rw-r--r--crates/proc-macro-srv/src/proc_macros.rs8
-rw-r--r--crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs17
-rw-r--r--crates/proc-macro-srv/src/tests/mod.rs344
-rw-r--r--crates/proc-macro-srv/src/tests/utils.rs34
-rw-r--r--crates/span/Cargo.toml3
-rw-r--r--crates/span/src/ast_id.rs903
-rw-r--r--crates/span/src/lib.rs24
-rw-r--r--crates/span/src/map.rs2
-rw-r--r--crates/syntax/src/ast/node_ext.rs10
57 files changed, 2256 insertions, 1945 deletions
diff --git a/.typos.toml b/.typos.toml
index e938bddd4b..cdbc003a80 100644
--- a/.typos.toml
+++ b/.typos.toml
@@ -18,6 +18,7 @@ extend-ignore-re = [
"INOUT",
"optin",
"=Pn",
+ "\\[[0-9A-F]{4},", # AstId hex hashes
# ignore `// spellchecker:off` until `// spellchecker:on`
"(?s)(#|//)\\s*spellchecker:off.*?\\n\\s*(#|//)\\s*spellchecker:on",
]
diff --git a/crates/hir-def/src/attr.rs b/crates/hir-def/src/attr.rs
index bb6222b1d4..a7328809a8 100644
--- a/crates/hir-def/src/attr.rs
+++ b/crates/hir-def/src/attr.rs
@@ -14,6 +14,7 @@ use intern::{Symbol, sym};
use la_arena::{ArenaMap, Idx, RawIdx};
use mbe::DelimiterKind;
use rustc_abi::ReprOptions;
+use span::AstIdNode;
use syntax::{
AstPtr,
ast::{self, HasAttrs},
@@ -22,10 +23,10 @@ use triomphe::Arc;
use tt::iter::{TtElement, TtIter};
use crate::{
- AdtId, AttrDefId, GenericParamId, HasModule, ItemTreeLoc, LocalFieldId, Lookup, MacroId,
+ AdtId, AstIdLoc, AttrDefId, GenericParamId, HasModule, LocalFieldId, Lookup, MacroId,
VariantId,
db::DefDatabase,
- item_tree::{AttrOwner, FieldParent, ItemTreeNode},
+ item_tree::AttrOwner,
lang_item::LangItem,
nameres::{ModuleOrigin, ModuleSource},
src::{HasChildSource, HasSource},
@@ -42,6 +43,15 @@ pub struct AttrsWithOwner {
}
impl Attrs {
+ pub fn new(
+ db: &dyn DefDatabase,
+ owner: &dyn ast::HasAttrs,
+ span_map: SpanMapRef<'_>,
+ cfg_options: &CfgOptions,
+ ) -> Self {
+ Attrs(RawAttrs::new_expanded(db, owner, span_map, cfg_options))
+ }
+
pub fn get(&self, id: AttrId) -> Option<&Attr> {
(**self).iter().find(|attr| attr.id == id)
}
@@ -94,44 +104,64 @@ impl Attrs {
v: VariantId,
) -> Arc<ArenaMap<LocalFieldId, Attrs>> {
let _p = tracing::info_span!("fields_attrs_query").entered();
- // FIXME: There should be some proper form of mapping between item tree field ids and hir field ids
let mut res = ArenaMap::default();
- let item_tree;
- let (parent, fields, krate) = match v {
+ let (fields, file_id, krate) = match v {
VariantId::EnumVariantId(it) => {
let loc = it.lookup(db);
let krate = loc.parent.lookup(db).container.krate;
- item_tree = loc.id.item_tree(db);
- let variant = &item_tree[loc.id.value];
- (FieldParent::EnumVariant(loc.id.value), &variant.fields, krate)
+ let source = loc.source(db);
+ (source.value.field_list(), source.file_id, krate)
}
VariantId::StructId(it) => {
let loc = it.lookup(db);
let krate = loc.container.krate;
- item_tree = loc.id.item_tree(db);
- let struct_ = &item_tree[loc.id.value];
- (FieldParent::Struct(loc.id.value), &struct_.fields, krate)
+ let source = loc.source(db);
+ (source.value.field_list(), source.file_id, krate)
}
VariantId::UnionId(it) => {
let loc = it.lookup(db);
let krate = loc.container.krate;
- item_tree = loc.id.item_tree(db);
- let union_ = &item_tree[loc.id.value];
- (FieldParent::Union(loc.id.value), &union_.fields, krate)
+ let source = loc.source(db);
+ (
+ source.value.record_field_list().map(ast::FieldList::RecordFieldList),
+ source.file_id,
+ krate,
+ )
}
};
+ let Some(fields) = fields else {
+ return Arc::new(res);
+ };
let cfg_options = krate.cfg_options(db);
-
- let mut idx = 0;
- for (id, _field) in fields.iter().enumerate() {
- let attrs = item_tree.attrs(db, krate, AttrOwner::make_field_indexed(parent, id));
- if attrs.is_cfg_enabled(cfg_options) {
- res.insert(Idx::from_raw(RawIdx::from(idx)), attrs);
- idx += 1;
+ let span_map = db.span_map(file_id);
+
+ match fields {
+ ast::FieldList::RecordFieldList(fields) => {
+ let mut idx = 0;
+ for field in fields.fields() {
+ let attrs =
+ Attrs(RawAttrs::new_expanded(db, &field, span_map.as_ref(), cfg_options));
+ if attrs.is_cfg_enabled(cfg_options).is_ok() {
+ res.insert(Idx::from_raw(RawIdx::from(idx)), attrs);
+ idx += 1;
+ }
+ }
+ }
+ ast::FieldList::TupleFieldList(fields) => {
+ let mut idx = 0;
+ for field in fields.fields() {
+ let attrs =
+ Attrs(RawAttrs::new_expanded(db, &field, span_map.as_ref(), cfg_options));
+ if attrs.is_cfg_enabled(cfg_options).is_ok() {
+ res.insert(Idx::from_raw(RawIdx::from(idx)), attrs);
+ idx += 1;
+ }
+ }
}
}
+ res.shrink_to_fit();
Arc::new(res)
}
}
@@ -167,11 +197,10 @@ impl Attrs {
}
#[inline]
- pub(crate) fn is_cfg_enabled(&self, cfg_options: &CfgOptions) -> bool {
- match self.cfg() {
- None => true,
- Some(cfg) => cfg_options.check(&cfg) != Some(false),
- }
+ pub(crate) fn is_cfg_enabled(&self, cfg_options: &CfgOptions) -> Result<(), CfgExpr> {
+ self.cfgs().try_for_each(|cfg| {
+ if cfg_options.check(&cfg) != Some(false) { Ok(()) } else { Err(cfg) }
+ })
}
#[inline]
@@ -488,12 +517,12 @@ impl AttrsWithOwner {
pub(crate) fn attrs_query(db: &dyn DefDatabase, def: AttrDefId) -> Attrs {
let _p = tracing::info_span!("attrs_query").entered();
// FIXME: this should use `Trace` to avoid duplication in `source_map` below
- let raw_attrs = match def {
+ match def {
AttrDefId::ModuleId(module) => {
let def_map = module.def_map(db);
let mod_data = &def_map[module.local_id];
- match mod_data.origin {
+ let raw_attrs = match mod_data.origin {
ModuleOrigin::File { definition, declaration_tree_id, .. } => {
let decl_attrs = declaration_tree_id
.item_tree(db)
@@ -515,34 +544,33 @@ impl AttrsWithOwner {
let tree = db.block_item_tree(id);
tree.raw_attrs(AttrOwner::TopLevel).clone()
}
- }
- }
- AttrDefId::FieldId(it) => {
- return db.fields_attrs(it.parent)[it.local_id].clone();
+ };
+ Attrs::expand_cfg_attr(db, module.krate, raw_attrs)
}
- AttrDefId::EnumVariantId(it) => attrs_from_item_tree_loc(db, it),
+ AttrDefId::FieldId(it) => db.fields_attrs(it.parent)[it.local_id].clone(),
+ AttrDefId::EnumVariantId(it) => attrs_from_ast_id_loc(db, it),
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),
- AdtId::UnionId(it) => attrs_from_item_tree_loc(db, it),
+ AdtId::StructId(it) => attrs_from_ast_id_loc(db, it),
+ AdtId::EnumId(it) => attrs_from_ast_id_loc(db, it),
+ AdtId::UnionId(it) => attrs_from_ast_id_loc(db, it),
},
- AttrDefId::TraitId(it) => attrs_from_item_tree_loc(db, it),
- AttrDefId::TraitAliasId(it) => attrs_from_item_tree_loc(db, it),
+ AttrDefId::TraitId(it) => attrs_from_ast_id_loc(db, it),
+ AttrDefId::TraitAliasId(it) => attrs_from_ast_id_loc(db, it),
AttrDefId::MacroId(it) => match it {
- MacroId::Macro2Id(it) => attrs_from_item_tree_loc(db, it),
- MacroId::MacroRulesId(it) => attrs_from_item_tree_loc(db, it),
- MacroId::ProcMacroId(it) => attrs_from_item_tree_loc(db, it),
+ MacroId::Macro2Id(it) => attrs_from_ast_id_loc(db, it),
+ MacroId::MacroRulesId(it) => attrs_from_ast_id_loc(db, it),
+ MacroId::ProcMacroId(it) => attrs_from_ast_id_loc(db, it),
},
- AttrDefId::ImplId(it) => attrs_from_item_tree_loc(db, it),
- AttrDefId::ConstId(it) => attrs_from_item_tree_loc(db, it),
- AttrDefId::StaticId(it) => attrs_from_item_tree_loc(db, it),
- AttrDefId::FunctionId(it) => attrs_from_item_tree_loc(db, it),
- AttrDefId::TypeAliasId(it) => attrs_from_item_tree_loc(db, it),
+ AttrDefId::ImplId(it) => attrs_from_ast_id_loc(db, it),
+ AttrDefId::ConstId(it) => attrs_from_ast_id_loc(db, it),
+ AttrDefId::StaticId(it) => attrs_from_ast_id_loc(db, it),
+ AttrDefId::FunctionId(it) => attrs_from_ast_id_loc(db, it),
+ AttrDefId::TypeAliasId(it) => attrs_from_ast_id_loc(db, it),
AttrDefId::GenericParamId(it) => match it {
GenericParamId::ConstParamId(it) => {
let src = it.parent().child_source(db);
// FIXME: We should be never getting `None` here.
- return Attrs(match src.value.get(it.local_id()) {
+ Attrs(match src.value.get(it.local_id()) {
Some(val) => RawAttrs::new_expanded(
db,
val,
@@ -550,12 +578,12 @@ impl AttrsWithOwner {
def.krate(db).cfg_options(db),
),
None => RawAttrs::EMPTY,
- });
+ })
}
GenericParamId::TypeParamId(it) => {
let src = it.parent().child_source(db);
// FIXME: We should be never getting `None` here.
- return Attrs(match src.value.get(it.local_id()) {
+ Attrs(match src.value.get(it.local_id()) {
Some(val) => RawAttrs::new_expanded(
db,
val,
@@ -563,12 +591,12 @@ impl AttrsWithOwner {
def.krate(db).cfg_options(db),
),
None => RawAttrs::EMPTY,
- });
+ })
}
GenericParamId::LifetimeParamId(it) => {
let src = it.parent.child_source(db);
// FIXME: We should be never getting `None` here.
- return Attrs(match src.value.get(it.local_id) {
+ Attrs(match src.value.get(it.local_id) {
Some(val) => RawAttrs::new_expanded(
db,
val,
@@ -576,16 +604,13 @@ impl AttrsWithOwner {
def.krate(db).cfg_options(db),
),
None => RawAttrs::EMPTY,
- });
+ })
}
},
- AttrDefId::ExternBlockId(it) => attrs_from_item_tree_loc(db, it),
- AttrDefId::ExternCrateId(it) => attrs_from_item_tree_loc(db, it),
- AttrDefId::UseId(it) => attrs_from_item_tree_loc(db, it),
- };
-
- let attrs = raw_attrs.expand_cfg_attr(db, def.krate(db));
- Attrs(attrs)
+ AttrDefId::ExternBlockId(it) => attrs_from_ast_id_loc(db, it),
+ AttrDefId::ExternCrateId(it) => attrs_from_ast_id_loc(db, it),
+ AttrDefId::UseId(it) => attrs_from_ast_id_loc(db, it),
+ }
}
pub fn source_map(&self, db: &dyn DefDatabase) -> AttrSourceMap {
@@ -787,14 +812,15 @@ fn any_has_attrs<'db>(
id.lookup(db).source(db).map(ast::AnyHasAttrs::new)
}
-fn attrs_from_item_tree_loc<'db, N: ItemTreeNode>(
+fn attrs_from_ast_id_loc<'db, N: AstIdNode + HasAttrs>(
db: &(dyn DefDatabase + 'db),
- lookup: impl Lookup<Database = dyn DefDatabase, Data = impl ItemTreeLoc<Id = N>>,
-) -> RawAttrs {
- let id = lookup.lookup(db).item_tree_id();
- let tree = id.item_tree(db);
- let attr_owner = N::attr_owner(id.value);
- tree.raw_attrs(attr_owner).clone()
+ lookup: impl Lookup<Database = dyn DefDatabase, Data = impl AstIdLoc<Ast = N> + HasModule>,
+) -> Attrs {
+ let loc = lookup.lookup(db);
+ let source = loc.source(db);
+ let span_map = db.span_map(source.file_id);
+ let cfg_options = loc.krate(db).cfg_options(db);
+ Attrs(RawAttrs::new_expanded(db, &source.value, span_map.as_ref(), cfg_options))
}
pub(crate) fn fields_attrs_source_map(
diff --git a/crates/hir-def/src/db.rs b/crates/hir-def/src/db.rs
index 4a9a3b12cf..362c0daa9b 100644
--- a/crates/hir-def/src/db.rs
+++ b/crates/hir-def/src/db.rs
@@ -1,8 +1,11 @@
//! Defines database & queries for name resolution.
use base_db::{Crate, RootQueryDb, SourceDatabase};
use either::Either;
-use hir_expand::{EditionedFileId, HirFileId, MacroCallId, MacroDefId, db::ExpandDatabase};
-use intern::sym;
+use hir_expand::{
+ EditionedFileId, HirFileId, InFile, Lookup, MacroCallId, MacroDefId, MacroDefKind,
+ db::ExpandDatabase,
+};
+use intern::{Symbol, sym};
use la_arena::ArenaMap;
use syntax::{AstPtr, ast};
use thin_vec::ThinVec;
@@ -11,8 +14,8 @@ use triomphe::Arc;
use crate::{
AttrDefId, BlockId, BlockLoc, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, EnumVariantId,
EnumVariantLoc, ExternBlockId, ExternBlockLoc, ExternCrateId, ExternCrateLoc, FunctionId,
- FunctionLoc, GenericDefId, ImplId, ImplLoc, LocalFieldId, Macro2Id, Macro2Loc, MacroId,
- MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ProcMacroId, ProcMacroLoc, StaticId,
+ FunctionLoc, GenericDefId, ImplId, ImplLoc, LocalFieldId, Macro2Id, Macro2Loc, MacroExpander,
+ MacroId, MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ProcMacroId, ProcMacroLoc, StaticId,
StaticLoc, StructId, StructLoc, TraitAliasId, TraitAliasLoc, TraitId, TraitLoc, TypeAliasId,
TypeAliasLoc, UnionId, UnionLoc, UseId, UseLoc, VariantId,
attr::{Attrs, AttrsWithOwner},
@@ -123,6 +126,8 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + SourceDatabase {
id: VariantId,
) -> (Arc<VariantFields>, Arc<ExpressionStoreSourceMap>);
+ // FIXME: Should we make this transparent? The only unstable thing in `enum_variants_with_diagnostics()`
+ // is ast ids, and ast ids are pretty stable now.
#[salsa::tracked]
fn enum_variants(&self, id: EnumId) -> Arc<EnumVariants> {
self.enum_variants_with_diagnostics(id).0
@@ -263,6 +268,9 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + SourceDatabase {
e: TypeAliasId,
) -> (Arc<TypeAliasSignature>, Arc<ExpressionStoreSourceMap>);
+ #[salsa::invoke(crate::signatures::extern_block_abi_query)]
+ fn extern_block_abi(&self, extern_block: ExternBlockId) -> Option<Symbol>;
+
// endregion:data
#[salsa::invoke(Body::body_with_source_map_query)]
@@ -399,10 +407,6 @@ fn crate_supports_no_std(db: &dyn DefDatabase, crate_id: Crate) -> bool {
}
fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId {
- use hir_expand::InFile;
-
- use crate::{Lookup, MacroDefKind, MacroExpander};
-
let kind = |expander, file_id, m| {
let in_file = InFile::new(file_id, m);
match expander {
@@ -418,11 +422,9 @@ fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId {
MacroId::Macro2Id(it) => {
let loc: Macro2Loc = it.lookup(db);
- let item_tree = loc.id.item_tree(db);
- let makro = &item_tree[loc.id.value];
MacroDefId {
krate: loc.container.krate,
- kind: kind(loc.expander, loc.id.file_id(), makro.ast_id.upcast()),
+ kind: kind(loc.expander, loc.id.file_id, loc.id.value.upcast()),
local_inner: false,
allow_internal_unsafe: loc.allow_internal_unsafe,
edition: loc.edition,
@@ -431,11 +433,9 @@ fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId {
MacroId::MacroRulesId(it) => {
let loc: MacroRulesLoc = it.lookup(db);
- let item_tree = loc.id.item_tree(db);
- let makro = &item_tree[loc.id.value];
MacroDefId {
krate: loc.container.krate,
- kind: kind(loc.expander, loc.id.file_id(), makro.ast_id.upcast()),
+ kind: kind(loc.expander, loc.id.file_id, loc.id.value.upcast()),
local_inner: loc.flags.contains(MacroRulesLocFlags::LOCAL_INNER),
allow_internal_unsafe: loc
.flags
@@ -446,15 +446,9 @@ fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId {
MacroId::ProcMacroId(it) => {
let loc = it.lookup(db);
- let item_tree = loc.id.item_tree(db);
- let makro = &item_tree[loc.id.value];
MacroDefId {
krate: loc.container.krate,
- kind: MacroDefKind::ProcMacro(
- InFile::new(loc.id.file_id(), makro.ast_id),
- loc.expander,
- loc.kind,
- ),
+ kind: MacroDefKind::ProcMacro(loc.id, loc.expander, loc.kind),
local_inner: false,
allow_internal_unsafe: false,
edition: loc.edition,
diff --git a/crates/hir-def/src/expr_store/expander.rs b/crates/hir-def/src/expr_store/expander.rs
index 3823fb5a1e..23b9712d1e 100644
--- a/crates/hir-def/src/expr_store/expander.rs
+++ b/crates/hir-def/src/expr_store/expander.rs
@@ -6,6 +6,7 @@ use base_db::Crate;
use cfg::CfgOptions;
use drop_bomb::DropBomb;
use hir_expand::AstId;
+use hir_expand::span_map::SpanMapRef;
use hir_expand::{
ExpandError, ExpandErrorKind, ExpandResult, HirFileId, InFile, Lookup, MacroCallId,
eager::EagerCallBackFn, mod_path::ModPath, span_map::SpanMap,
@@ -223,9 +224,15 @@ impl Expander {
}
}
+ #[inline]
pub(super) fn ast_id_map(&self) -> &AstIdMap {
&self.ast_id_map
}
+
+ #[inline]
+ pub(super) fn span_map(&self) -> SpanMapRef<'_> {
+ self.span_map.as_ref()
+ }
}
#[derive(Debug)]
diff --git a/crates/hir-def/src/expr_store/lower.rs b/crates/hir-def/src/expr_store/lower.rs
index 29871f5e04..89eeaf00bc 100644
--- a/crates/hir-def/src/expr_store/lower.rs
+++ b/crates/hir-def/src/expr_store/lower.rs
@@ -10,9 +10,10 @@ use std::mem;
use cfg::CfgOptions;
use either::Either;
use hir_expand::{
- HirFileId, InFile, Lookup, MacroDefId,
+ HirFileId, InFile, MacroDefId,
mod_path::tool_path,
name::{AsName, Name},
+ span_map::SpanMapRef,
};
use intern::{Symbol, sym};
use rustc_hash::FxHashMap;
@@ -30,8 +31,8 @@ use triomphe::Arc;
use tt::TextRange;
use crate::{
- AdtId, BlockId, BlockLoc, DefWithBodyId, FunctionId, GenericDefId, ImplId, ItemTreeLoc,
- MacroId, ModuleDefId, ModuleId, TraitAliasId, TraitId, TypeAliasId, UnresolvedMacro,
+ AdtId, BlockId, BlockLoc, DefWithBodyId, FunctionId, GenericDefId, ImplId, MacroId,
+ ModuleDefId, ModuleId, TraitAliasId, TraitId, TypeAliasId, UnresolvedMacro,
builtin_type::BuiltinUint,
db::DefDatabase,
expr_store::{
@@ -564,6 +565,11 @@ impl ExprCollector<'_> {
}
}
+ #[inline]
+ pub(crate) fn span_map(&self) -> SpanMapRef<'_> {
+ self.expander.span_map()
+ }
+
pub fn lower_lifetime_ref(&mut self, lifetime: ast::Lifetime) -> LifetimeRefId {
// FIXME: Keyword check?
let lifetime_ref = match &*lifetime.text() {
@@ -2141,26 +2147,10 @@ impl ExprCollector<'_> {
block: ast::BlockExpr,
mk_block: impl FnOnce(Option<BlockId>, Box<[Statement]>, Option<ExprId>) -> Expr,
) -> ExprId {
- let block_has_items = {
- let statement_has_item = block.statements().any(|stmt| match stmt {
- ast::Stmt::Item(_) => true,
- // Macro calls can be both items and expressions. The syntax library always treats
- // them as expressions here, so we undo that.
- ast::Stmt::ExprStmt(es) => matches!(es.expr(), Some(ast::Expr::MacroExpr(_))),
- _ => false,
- });
- statement_has_item
- || matches!(block.tail_expr(), Some(ast::Expr::MacroExpr(_)))
- || (block.may_carry_attributes() && block.attrs().next().is_some())
- };
-
- let block_id = if block_has_items {
- let file_local_id = self.expander.ast_id_map().ast_id(&block);
+ let block_id = self.expander.ast_id_map().ast_id_for_block(&block).map(|file_local_id| {
let ast_id = self.expander.in_file(file_local_id);
- Some(self.db.intern_block(BlockLoc { ast_id, module: self.module }))
- } else {
- None
- };
+ self.db.intern_block(BlockLoc { ast_id, module: self.module })
+ });
let (module, def_map) =
match block_id.map(|block_id| (block_def_map(self.db, block_id), block_id)) {
@@ -2260,11 +2250,8 @@ impl ExprCollector<'_> {
match resolved.take_values() {
Some(ModuleDefId::ConstId(_)) => (None, Pat::Path(name.into())),
Some(ModuleDefId::EnumVariantId(variant))
- if {
- let loc = variant.lookup(self.db);
- let tree = loc.item_tree_id().item_tree(self.db);
- tree[loc.id.value].shape != FieldsShape::Record
- } =>
+ // FIXME: This can cause a cycle if the user is writing invalid code
+ if self.db.variant_fields(variant.into()).shape != FieldsShape::Record =>
{
(None, Pat::Path(name.into()))
}
diff --git a/crates/hir-def/src/expr_store/pretty.rs b/crates/hir-def/src/expr_store/pretty.rs
index f12a9b7a54..7b452721df 100644
--- a/crates/hir-def/src/expr_store/pretty.rs
+++ b/crates/hir-def/src/expr_store/pretty.rs
@@ -9,9 +9,10 @@ use std::{
use hir_expand::{Lookup, mod_path::PathKind};
use itertools::Itertools;
use span::Edition;
+use syntax::ast::HasName;
use crate::{
- AdtId, DefWithBodyId, GenericDefId, ItemTreeLoc, TypeParamId, VariantId,
+ AdtId, DefWithBodyId, GenericDefId, TypeParamId, VariantId,
expr_store::path::{GenericArg, GenericArgs},
hir::{
Array, BindingAnnotation, CaptureBy, ClosureKind, Literal, Movability, Statement,
@@ -19,6 +20,7 @@ use crate::{
},
lang_item::LangItemTarget,
signatures::{FnFlags, FunctionSignature, StructSignature},
+ src::HasSource,
type_ref::{ConstRef, LifetimeRef, Mutability, TraitBoundModifier, TypeBound, UseArgRef},
};
use crate::{LifetimeParamId, signatures::StructFlags};
@@ -48,6 +50,17 @@ pub enum LineFormat {
Indentation,
}
+fn item_name<Id, Loc>(db: &dyn DefDatabase, id: Id, default: &str) -> String
+where
+ Id: Lookup<Database = dyn DefDatabase, Data = Loc>,
+ Loc: HasSource,
+ Loc::Value: ast::HasName,
+{
+ let loc = id.lookup(db);
+ let source = loc.source(db);
+ source.value.name().map_or_else(|| default.to_owned(), |name| name.to_string())
+}
+
pub fn print_body_hir(
db: &dyn DefDatabase,
body: &Body,
@@ -55,31 +68,14 @@ pub fn print_body_hir(
edition: Edition,
) -> String {
let header = match owner {
- DefWithBodyId::FunctionId(it) => {
- it.lookup(db).id.resolved(db, |it| format!("fn {}", it.name.display(db, edition)))
- }
- DefWithBodyId::StaticId(it) => it
- .lookup(db)
- .id
- .resolved(db, |it| format!("static {} = ", it.name.display(db, edition))),
- DefWithBodyId::ConstId(it) => it.lookup(db).id.resolved(db, |it| {
- format!(
- "const {} = ",
- match &it.name {
- Some(name) => name.display(db, edition).to_string(),
- None => "_".to_owned(),
- }
- )
- }),
- DefWithBodyId::VariantId(it) => {
- 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, edition),
- loc.id.item_tree(db)[loc.id.value].name.display(db, edition),
- )
- }
+ DefWithBodyId::FunctionId(it) => format!("fn {}", item_name(db, it, "<missing>")),
+ DefWithBodyId::StaticId(it) => format!("static {} = ", item_name(db, it, "<missing>")),
+ DefWithBodyId::ConstId(it) => format!("const {} = ", item_name(db, it, "_")),
+ DefWithBodyId::VariantId(it) => format!(
+ "enum {}::{}",
+ item_name(db, it.lookup(db).parent, "<missing>"),
+ item_name(db, it, "<missing>")
+ ),
};
let mut p = Printer {
@@ -116,22 +112,13 @@ pub fn print_body_hir(
pub fn print_variant_body_hir(db: &dyn DefDatabase, owner: VariantId, edition: Edition) -> String {
let header = match owner {
- VariantId::StructId(it) => {
- it.lookup(db).id.resolved(db, |it| format!("struct {}", it.name.display(db, edition)))
- }
- VariantId::EnumVariantId(enum_variant_id) => {
- let loc = enum_variant_id.lookup(db);
- let enum_loc = loc.parent.lookup(db);
- format!(
- "enum {}::{}",
- enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db, edition),
- loc.id.item_tree(db)[loc.id.value].name.display(db, edition),
- )
- }
- VariantId::UnionId(union_id) => union_id
- .lookup(db)
- .id
- .resolved(db, |it| format!("union {}", it.name.display(db, edition))),
+ VariantId::StructId(it) => format!("struct {}", item_name(db, it, "<missing>")),
+ VariantId::EnumVariantId(it) => format!(
+ "enum {}::{}",
+ item_name(db, it.lookup(db).parent, "<missing>"),
+ item_name(db, it, "<missing>")
+ ),
+ VariantId::UnionId(it) => format!("union {}", item_name(db, it, "<missing>")),
};
let fields = db.variant_fields(owner);
@@ -1089,10 +1076,7 @@ impl Printer<'_> {
w!(self, "builtin#lang(");
macro_rules! write_name {
($it:ident) => {{
- let loc = $it.lookup(self.db);
- let tree = loc.item_tree_id().item_tree(self.db);
- let name = &tree[loc.id.value].name;
- w!(self, "{}", name.display(self.db, self.edition));
+ w!(self, "{}", item_name(self.db, $it, "<missing>"));
}};
}
match *it {
diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs
index 1b97eb72b6..07d1500fc0 100644
--- a/crates/hir-def/src/item_tree.rs
+++ b/crates/hir-def/src/item_tree.rs
@@ -29,7 +29,6 @@
//!
//! In general, any item in the `ItemTree` stores its `AstId`, which allows mapping it back to its
//! surface syntax.
-#![allow(unexpected_cfgs)]
mod lower;
mod pretty;
@@ -46,12 +45,12 @@ use std::{
use ast::{AstNode, StructKind};
use base_db::Crate;
use hir_expand::{
- ExpandTo, HirFileId, InFile,
+ ExpandTo, HirFileId,
attrs::RawAttrs,
mod_path::{ModPath, PathKind},
name::Name,
};
-use intern::{Interned, Symbol};
+use intern::Interned;
use la_arena::{Arena, Idx, RawIdx};
use rustc_hash::FxHashMap;
use smallvec::SmallVec;
@@ -62,6 +61,8 @@ use triomphe::Arc;
use crate::{BlockId, Lookup, attr::Attrs, db::DefDatabase};
+pub(crate) use crate::item_tree::lower::{lower_use_tree, visibility_from_ast};
+
#[derive(Copy, Clone, Eq, PartialEq)]
pub struct RawVisibilityId(u32);
@@ -235,7 +236,6 @@ impl ItemTree {
structs,
unions,
enums,
- variants,
consts,
statics,
traits,
@@ -256,7 +256,6 @@ impl ItemTree {
structs.shrink_to_fit();
unions.shrink_to_fit();
enums.shrink_to_fit();
- variants.shrink_to_fit();
consts.shrink_to_fit();
statics.shrink_to_fit();
traits.shrink_to_fit();
@@ -308,7 +307,6 @@ struct ItemTreeData {
structs: Arena<Struct>,
unions: Arena<Union>,
enums: Arena<Enum>,
- variants: Arena<Variant>,
consts: Arena<Const>,
statics: Arena<Static>,
traits: Arena<Trait>,
@@ -338,41 +336,15 @@ pub enum AttrOwner {
ModItem(ModItem),
/// Inner attributes of the source file.
TopLevel,
-
- Variant(FileItemTreeId<Variant>),
- // while not relevant to early name resolution, fields can contain visibility
- Field(FieldParent, ItemTreeFieldId),
}
-impl AttrOwner {
- pub fn make_field_indexed(parent: FieldParent, idx: usize) -> Self {
- AttrOwner::Field(parent, ItemTreeFieldId::from_raw(RawIdx::from_u32(idx as u32)))
+impl From<ModItem> for AttrOwner {
+ #[inline]
+ fn from(value: ModItem) -> Self {
+ AttrOwner::ModItem(value)
}
}
-#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
-pub enum FieldParent {
- Struct(FileItemTreeId<Struct>),
- Union(FileItemTreeId<Union>),
- EnumVariant(FileItemTreeId<Variant>),
-}
-
-pub type ItemTreeFieldId = Idx<Field>;
-
-macro_rules! from_attrs {
- ( $( $var:ident($t:ty) ),+ $(,)? ) => {
- $(
- impl From<$t> for AttrOwner {
- fn from(t: $t) -> AttrOwner {
- AttrOwner::$var(t)
- }
- }
- )+
- };
-}
-
-from_attrs!(ModItem(ModItem), Variant(FileItemTreeId<Variant>));
-
/// Trait implemented by all nodes in the item tree.
pub trait ItemTreeNode: Clone {
type Source: AstIdNode;
@@ -381,7 +353,6 @@ pub trait ItemTreeNode: Clone {
/// Looks up an instance of `Self` in an item tree.
fn lookup(tree: &ItemTree, index: Idx<Self>) -> &Self;
- fn attr_owner(id: FileItemTreeId<Self>) -> AttrOwner;
}
pub struct FileItemTreeId<N>(Idx<N>);
@@ -446,6 +417,7 @@ impl TreeId {
}
}
+ #[inline]
pub fn file_id(self) -> HirFileId {
self.file
}
@@ -544,10 +516,6 @@ macro_rules! mod_items {
fn lookup(tree: &ItemTree, index: Idx<Self>) -> &Self {
&tree.data().$fld[index]
}
-
- fn attr_owner(id: FileItemTreeId<Self>) -> AttrOwner {
- AttrOwner::ModItem(ModItem::$typ(id))
- }
}
impl Index<Idx<$typ>> for ItemTree {
@@ -621,22 +589,6 @@ impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree {
}
}
-impl ItemTreeNode for Variant {
- type Source = ast::Variant;
-
- fn ast_id(&self) -> FileAstId<Self::Source> {
- self.ast_id
- }
-
- fn lookup(tree: &ItemTree, index: Idx<Self>) -> &Self {
- &tree.data().variants[index]
- }
-
- fn attr_owner(id: FileItemTreeId<Self>) -> AttrOwner {
- AttrOwner::Variant(id)
- }
-}
-
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Use {
pub visibility: RawVisibilityId,
@@ -709,7 +661,6 @@ pub struct ExternCrate {
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct ExternBlock {
- pub abi: Option<Symbol>,
pub ast_id: FileAstId<ast::ExternBlock>,
pub children: Box<[ModItem]>,
}
@@ -725,7 +676,6 @@ pub struct Function {
pub struct Struct {
pub name: Name,
pub visibility: RawVisibilityId,
- pub fields: Box<[Field]>,
pub shape: FieldsShape,
pub ast_id: FileAstId<ast::Struct>,
}
@@ -734,7 +684,6 @@ pub struct Struct {
pub struct Union {
pub name: Name,
pub visibility: RawVisibilityId,
- pub fields: Box<[Field]>,
pub ast_id: FileAstId<ast::Union>,
}
@@ -742,18 +691,9 @@ pub struct Union {
pub struct Enum {
pub name: Name,
pub visibility: RawVisibilityId,
- pub variants: Range<FileItemTreeId<Variant>>,
pub ast_id: FileAstId<ast::Enum>,
}
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct Variant {
- pub name: Name,
- pub fields: Box<[Field]>,
- pub shape: FieldsShape,
- pub ast_id: FileAstId<ast::Variant>,
-}
-
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum FieldsShape {
Record,
@@ -785,16 +725,6 @@ impl VisibilityExplicitness {
}
}
-// FIXME: Remove this from item tree?
-/// A single field of an enum variant or struct
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct Field {
- pub name: Name,
- pub visibility: RawVisibilityId,
- // FIXME: Not an item tree property
- pub is_unsafe: bool,
-}
-
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Const {
/// `None` for `const _: () = ();`
@@ -814,7 +744,6 @@ pub struct Static {
pub struct Trait {
pub name: Name,
pub visibility: RawVisibilityId,
- pub items: Box<[AssocItem]>,
pub ast_id: FileAstId<ast::Trait>,
}
@@ -827,7 +756,6 @@ pub struct TraitAlias {
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Impl {
- pub items: Box<[AssocItem]>,
pub ast_id: FileAstId<ast::Impl>,
}
@@ -878,43 +806,6 @@ pub struct Macro2 {
pub ast_id: FileAstId<ast::MacroDef>,
}
-impl Use {
- /// Maps a `UseTree` contained in this import back to its AST node.
- pub fn use_tree_to_ast(
- &self,
- db: &dyn DefDatabase,
- file_id: HirFileId,
- index: Idx<ast::UseTree>,
- ) -> ast::UseTree {
- // Re-lower the AST item and get the source map.
- // Note: The AST unwraps are fine, since if they fail we should have never obtained `index`.
- let ast = InFile::new(file_id, self.ast_id).to_node(db);
- let ast_use_tree = ast.use_tree().expect("missing `use_tree`");
- let (_, source_map) = lower::lower_use_tree(db, ast_use_tree, &mut |range| {
- db.span_map(file_id).span_for_range(range).ctx
- })
- .expect("failed to lower use tree");
- source_map[index].clone()
- }
-
- /// Maps a `UseTree` contained in this import back to its AST node.
- pub fn use_tree_source_map(
- &self,
- db: &dyn DefDatabase,
- file_id: HirFileId,
- ) -> Arena<ast::UseTree> {
- // Re-lower the AST item and get the source map.
- // Note: The AST unwraps are fine, since if they fail we should have never obtained `index`.
- let ast = InFile::new(file_id, self.ast_id).to_node(db);
- let ast_use_tree = ast.use_tree().expect("missing `use_tree`");
- lower::lower_use_tree(db, ast_use_tree, &mut |range| {
- db.span_map(file_id).span_for_range(range).ctx
- })
- .expect("failed to lower use tree")
- .1
- }
-}
-
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ImportKind {
/// The `ModPath` is imported normally.
@@ -1005,76 +896,3 @@ impl UseTree {
}
}
}
-
-macro_rules! impl_froms {
- ($e:ident { $($v:ident ($t:ty)),* $(,)? }) => {
- $(
- impl From<$t> for $e {
- fn from(it: $t) -> $e {
- $e::$v(it)
- }
- }
- )*
- }
-}
-
-impl ModItem {
- pub fn as_assoc_item(&self) -> Option<AssocItem> {
- match self {
- ModItem::Use(_)
- | ModItem::ExternCrate(_)
- | ModItem::ExternBlock(_)
- | ModItem::Struct(_)
- | ModItem::Union(_)
- | ModItem::Enum(_)
- | ModItem::Static(_)
- | ModItem::Trait(_)
- | ModItem::TraitAlias(_)
- | ModItem::Impl(_)
- | ModItem::Mod(_)
- | ModItem::MacroRules(_)
- | ModItem::Macro2(_) => None,
- &ModItem::MacroCall(call) => Some(AssocItem::MacroCall(call)),
- &ModItem::Const(konst) => Some(AssocItem::Const(konst)),
- &ModItem::TypeAlias(alias) => Some(AssocItem::TypeAlias(alias)),
- &ModItem::Function(func) => Some(AssocItem::Function(func)),
- }
- }
-}
-
-#[derive(Debug, Copy, Clone, Eq, PartialEq)]
-pub enum AssocItem {
- Function(FileItemTreeId<Function>),
- TypeAlias(FileItemTreeId<TypeAlias>),
- Const(FileItemTreeId<Const>),
- MacroCall(FileItemTreeId<MacroCall>),
-}
-
-impl_froms!(AssocItem {
- Function(FileItemTreeId<Function>),
- TypeAlias(FileItemTreeId<TypeAlias>),
- Const(FileItemTreeId<Const>),
- MacroCall(FileItemTreeId<MacroCall>),
-});
-
-impl From<AssocItem> for ModItem {
- fn from(item: AssocItem) -> Self {
- match item {
- AssocItem::Function(it) => it.into(),
- AssocItem::TypeAlias(it) => it.into(),
- AssocItem::Const(it) => it.into(),
- AssocItem::MacroCall(it) => it.into(),
- }
- }
-}
-
-impl AssocItem {
- pub fn ast_id(self, tree: &ItemTree) -> FileAstId<ast::AssocItem> {
- match self {
- AssocItem::Function(id) => tree[id].ast_id.upcast(),
- AssocItem::TypeAlias(id) => tree[id].ast_id.upcast(),
- AssocItem::Const(id) => tree[id].ast_id.upcast(),
- AssocItem::MacroCall(id) => tree[id].ast_id.upcast(),
- }
- }
-}
diff --git a/crates/hir-def/src/item_tree/lower.rs b/crates/hir-def/src/item_tree/lower.rs
index b490e1683c..d9588cb487 100644
--- a/crates/hir-def/src/item_tree/lower.rs
+++ b/crates/hir-def/src/item_tree/lower.rs
@@ -8,23 +8,22 @@ use hir_expand::{
name::AsName,
span_map::{SpanMap, SpanMapRef},
};
-use intern::{Symbol, sym};
use la_arena::Arena;
use span::{AstIdMap, SyntaxContext};
use syntax::{
AstNode,
- ast::{self, HasModuleItem, HasName, IsString},
+ ast::{self, HasModuleItem, HasName},
};
use triomphe::Arc;
use crate::{
db::DefDatabase,
item_tree::{
- AssocItem, AttrOwner, Const, Enum, ExternBlock, ExternCrate, Field, FieldParent,
- FieldsShape, FileItemTreeId, Function, Idx, Impl, ImportAlias, Interned, ItemTree,
- ItemTreeData, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, ModPath, Name, Range,
- RawAttrs, RawIdx, RawVisibility, RawVisibilityId, Static, Struct, StructKind, Trait,
- TraitAlias, TypeAlias, Union, Use, UseTree, UseTreeKind, Variant, VisibilityExplicitness,
+ AttrOwner, Const, Enum, ExternBlock, ExternCrate, FieldsShape, FileItemTreeId, Function,
+ Idx, Impl, ImportAlias, Interned, ItemTree, ItemTreeData, Macro2, MacroCall, MacroRules,
+ Mod, ModItem, ModKind, ModPath, RawAttrs, RawVisibility, RawVisibilityId, Static, Struct,
+ StructKind, Trait, TraitAlias, TypeAlias, Union, Use, UseTree, UseTreeKind,
+ VisibilityExplicitness,
},
};
@@ -163,118 +162,23 @@ impl<'a> Ctx<'a> {
}
}
- fn lower_assoc_item(&mut self, item_node: &ast::AssocItem) -> Option<AssocItem> {
- let item: AssocItem = match item_node {
- ast::AssocItem::Fn(ast) => self.lower_function(ast).map(Into::into),
- ast::AssocItem::TypeAlias(ast) => self.lower_type_alias(ast).map(Into::into),
- ast::AssocItem::Const(ast) => Some(self.lower_const(ast).into()),
- ast::AssocItem::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into),
- }?;
- let attrs = RawAttrs::new(self.db, item_node, self.span_map());
- self.add_attrs(
- match item {
- AssocItem::Function(it) => AttrOwner::ModItem(ModItem::Function(it)),
- AssocItem::TypeAlias(it) => AttrOwner::ModItem(ModItem::TypeAlias(it)),
- AssocItem::Const(it) => AttrOwner::ModItem(ModItem::Const(it)),
- AssocItem::MacroCall(it) => AttrOwner::ModItem(ModItem::MacroCall(it)),
- },
- attrs,
- );
- Some(item)
- }
-
fn lower_struct(&mut self, strukt: &ast::Struct) -> Option<FileItemTreeId<Struct>> {
let visibility = self.lower_visibility(strukt);
let name = strukt.name()?.as_name();
let ast_id = self.source_ast_id_map.ast_id(strukt);
- let (fields, kind, attrs) = self.lower_fields(&strukt.kind());
- let res = Struct { name, visibility, fields, shape: kind, ast_id };
+ let shape = adt_shape(strukt.kind());
+ let res = Struct { name, visibility, shape, ast_id };
let id = id(self.data().structs.alloc(res));
- for (idx, attr) in attrs {
- self.add_attrs(
- AttrOwner::Field(
- FieldParent::Struct(id),
- Idx::from_raw(RawIdx::from_u32(idx as u32)),
- ),
- attr,
- );
- }
Some(id)
}
- fn lower_fields(
- &mut self,
- strukt_kind: &ast::StructKind,
- ) -> (Box<[Field]>, FieldsShape, Vec<(usize, RawAttrs)>) {
- match strukt_kind {
- ast::StructKind::Record(it) => {
- let mut fields = vec![];
- let mut attrs = vec![];
-
- for (i, field) in it.fields().enumerate() {
- let data = self.lower_record_field(&field);
- fields.push(data);
- let attr = RawAttrs::new(self.db, &field, self.span_map());
- if !attr.is_empty() {
- attrs.push((i, attr))
- }
- }
- (fields.into(), FieldsShape::Record, attrs)
- }
- ast::StructKind::Tuple(it) => {
- let mut fields = vec![];
- let mut attrs = vec![];
-
- for (i, field) in it.fields().enumerate() {
- let data = self.lower_tuple_field(i, &field);
- fields.push(data);
- let attr = RawAttrs::new(self.db, &field, self.span_map());
- if !attr.is_empty() {
- attrs.push((i, attr))
- }
- }
- (fields.into(), FieldsShape::Tuple, attrs)
- }
- ast::StructKind::Unit => (Box::default(), FieldsShape::Unit, Vec::default()),
- }
- }
-
- fn lower_record_field(&mut self, field: &ast::RecordField) -> Field {
- let name = match field.name() {
- Some(name) => name.as_name(),
- None => Name::missing(),
- };
- let visibility = self.lower_visibility(field);
-
- Field { name, visibility, is_unsafe: field.unsafe_token().is_some() }
- }
-
- fn lower_tuple_field(&mut self, idx: usize, field: &ast::TupleField) -> Field {
- let name = Name::new_tuple_field(idx);
- let visibility = self.lower_visibility(field);
- Field { name, visibility, is_unsafe: false }
- }
-
fn lower_union(&mut self, union: &ast::Union) -> Option<FileItemTreeId<Union>> {
let visibility = self.lower_visibility(union);
let name = union.name()?.as_name();
let ast_id = self.source_ast_id_map.ast_id(union);
- let (fields, _, attrs) = match union.record_field_list() {
- Some(record_field_list) => self.lower_fields(&StructKind::Record(record_field_list)),
- None => (Box::default(), FieldsShape::Record, Vec::default()),
- };
- let res = Union { name, visibility, fields, ast_id };
+ let res = Union { name, visibility, ast_id };
let id = id(self.data().unions.alloc(res));
- for (idx, attr) in attrs {
- self.add_attrs(
- AttrOwner::Field(
- FieldParent::Union(id),
- Idx::from_raw(RawIdx::from_u32(idx as u32)),
- ),
- attr,
- );
- }
Some(id)
}
@@ -282,48 +186,11 @@ impl<'a> Ctx<'a> {
let visibility = self.lower_visibility(enum_);
let name = enum_.name()?.as_name();
let ast_id = self.source_ast_id_map.ast_id(enum_);
- let variants = match &enum_.variant_list() {
- Some(variant_list) => self.lower_variants(variant_list),
- None => {
- FileItemTreeId(self.next_variant_idx())..FileItemTreeId(self.next_variant_idx())
- }
- };
- let res = Enum { name, visibility, variants, ast_id };
+ let res = Enum { name, visibility, ast_id };
let id = id(self.data().enums.alloc(res));
Some(id)
}
- fn lower_variants(&mut self, variants: &ast::VariantList) -> Range<FileItemTreeId<Variant>> {
- let start = self.next_variant_idx();
- for variant in variants.variants() {
- let idx = self.lower_variant(&variant);
- self.add_attrs(id(idx).into(), RawAttrs::new(self.db, &variant, self.span_map()));
- }
- let end = self.next_variant_idx();
- FileItemTreeId(start)..FileItemTreeId(end)
- }
-
- fn lower_variant(&mut self, variant: &ast::Variant) -> Idx<Variant> {
- let name = match variant.name() {
- Some(name) => name.as_name(),
- None => Name::missing(),
- };
- let (fields, kind, attrs) = self.lower_fields(&variant.kind());
- let ast_id = self.source_ast_id_map.ast_id(variant);
- let res = Variant { name, fields, shape: kind, ast_id };
- let id = self.data().variants.alloc(res);
- for (idx, attr) in attrs {
- self.add_attrs(
- AttrOwner::Field(
- FieldParent::EnumVariant(FileItemTreeId(id)),
- Idx::from_raw(RawIdx::from_u32(idx as u32)),
- ),
- attr,
- );
- }
- id
- }
-
fn lower_function(&mut self, func: &ast::Fn) -> Option<FileItemTreeId<Function>> {
let visibility = self.lower_visibility(func);
let name = func.name()?.as_name();
@@ -390,14 +257,7 @@ impl<'a> Ctx<'a> {
let visibility = self.lower_visibility(trait_def);
let ast_id = self.source_ast_id_map.ast_id(trait_def);
- let items = trait_def
- .assoc_item_list()
- .into_iter()
- .flat_map(|list| list.assoc_items())
- .filter_map(|item_node| self.lower_assoc_item(&item_node))
- .collect();
-
- let def = Trait { name, visibility, items, ast_id };
+ let def = Trait { name, visibility, ast_id };
let id = id(self.data().traits.alloc(def));
Some(id)
}
@@ -417,16 +277,9 @@ impl<'a> Ctx<'a> {
fn lower_impl(&mut self, impl_def: &ast::Impl) -> FileItemTreeId<Impl> {
let ast_id = self.source_ast_id_map.ast_id(impl_def);
- // We cannot use `assoc_items()` here as that does not include macro calls.
- let items = impl_def
- .assoc_item_list()
- .into_iter()
- .flat_map(|it| it.assoc_items())
- .filter_map(|item| self.lower_assoc_item(&item))
- .collect();
// Note that trait impls don't get implicit `Self` unlike traits, because here they are a
// type alias rather than a type parameter, so this is handled by the resolver.
- let res = Impl { items, ast_id };
+ let res = Impl { ast_id };
id(self.data().impls.alloc(res))
}
@@ -489,7 +342,6 @@ impl<'a> Ctx<'a> {
fn lower_extern_block(&mut self, block: &ast::ExternBlock) -> FileItemTreeId<ExternBlock> {
let ast_id = self.source_ast_id_map.ast_id(block);
- let abi = block.abi().map(lower_abi);
let children: Box<[_]> = block.extern_item_list().map_or(Box::new([]), |list| {
list.extern_items()
.filter_map(|item| {
@@ -510,7 +362,7 @@ impl<'a> Ctx<'a> {
.collect()
});
- let res = ExternBlock { abi, ast_id, children };
+ let res = ExternBlock { ast_id, children };
id(self.data().extern_blocks.alloc(res))
}
@@ -520,20 +372,6 @@ impl<'a> Ctx<'a> {
});
self.data().vis.alloc(vis)
}
-
- fn next_variant_idx(&self) -> Idx<Variant> {
- Idx::from_raw(RawIdx::from(
- self.tree.data.as_ref().map_or(0, |data| data.variants.len() as u32),
- ))
- }
-}
-
-fn lower_abi(abi: ast::Abi) -> Symbol {
- match abi.abi_string() {
- Some(tok) => Symbol::intern(tok.text_without_quotes()),
- // `extern` default to be `extern "C"`.
- _ => sym::C,
- }
}
struct UseTreeLowering<'a> {
@@ -626,7 +464,7 @@ fn private_vis() -> RawVisibility {
)
}
-fn visibility_from_ast(
+pub(crate) fn visibility_from_ast(
db: &dyn DefDatabase,
node: Option<ast::Visibility>,
span_for_range: &mut dyn FnMut(::tt::TextRange) -> SyntaxContext,
@@ -647,3 +485,11 @@ fn visibility_from_ast(
};
RawVisibility::Module(Interned::new(path), VisibilityExplicitness::Explicit)
}
+
+fn adt_shape(kind: StructKind) -> FieldsShape {
+ match kind {
+ StructKind::Record(_) => FieldsShape::Record,
+ StructKind::Tuple(_) => FieldsShape::Tuple,
+ StructKind::Unit => FieldsShape::Unit,
+ }
+}
diff --git a/crates/hir-def/src/item_tree/pretty.rs b/crates/hir-def/src/item_tree/pretty.rs
index 47c6eb1329..0c62b86dae 100644
--- a/crates/hir-def/src/item_tree/pretty.rs
+++ b/crates/hir-def/src/item_tree/pretty.rs
@@ -2,15 +2,13 @@
use std::fmt::{self, Write};
-use la_arena::{Idx, RawIdx};
use span::{Edition, ErasedFileAstId};
use crate::{
item_tree::{
- AttrOwner, Const, DefDatabase, Enum, ExternBlock, ExternCrate, Field, FieldParent,
- FieldsShape, FileItemTreeId, Function, Impl, ItemTree, Macro2, MacroCall, MacroRules, Mod,
- ModItem, ModKind, RawAttrs, RawVisibilityId, Static, Struct, Trait, TraitAlias, TypeAlias,
- Union, Use, UseTree, UseTreeKind, Variant,
+ AttrOwner, Const, DefDatabase, Enum, ExternBlock, ExternCrate, FieldsShape, Function, Impl,
+ ItemTree, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, RawAttrs, RawVisibilityId,
+ Static, Struct, Trait, TraitAlias, TypeAlias, Union, Use, UseTree, UseTreeKind,
},
visibility::RawVisibility,
};
@@ -118,44 +116,14 @@ impl Printer<'_> {
};
}
- fn print_fields(&mut self, parent: FieldParent, kind: FieldsShape, fields: &[Field]) {
- let edition = self.edition;
+ fn print_fields(&mut self, kind: FieldsShape) {
match kind {
FieldsShape::Record => {
self.whitespace();
- w!(self, "{{");
- self.indented(|this| {
- for (idx, Field { name, visibility, is_unsafe }) in fields.iter().enumerate() {
- this.print_attrs_of(
- AttrOwner::Field(parent, Idx::from_raw(RawIdx::from(idx as u32))),
- "\n",
- );
- this.print_visibility(*visibility);
- if *is_unsafe {
- w!(this, "unsafe ");
- }
-
- wln!(this, "{},", name.display(self.db, edition));
- }
- });
- w!(self, "}}");
+ w!(self, "{{ ... }}");
}
FieldsShape::Tuple => {
- w!(self, "(");
- self.indented(|this| {
- for (idx, Field { name, visibility, is_unsafe }) in fields.iter().enumerate() {
- this.print_attrs_of(
- AttrOwner::Field(parent, Idx::from_raw(RawIdx::from(idx as u32))),
- "\n",
- );
- this.print_visibility(*visibility);
- if *is_unsafe {
- w!(this, "unsafe ");
- }
- wln!(this, "{},", name.display(self.db, edition));
- }
- });
- w!(self, ")");
+ w!(self, "(...)");
}
FieldsShape::Unit => {}
}
@@ -214,13 +182,9 @@ impl Printer<'_> {
wln!(self, ";");
}
ModItem::ExternBlock(it) => {
- let ExternBlock { abi, ast_id, children } = &self.tree[it];
+ let ExternBlock { ast_id, children } = &self.tree[it];
self.print_ast_id(ast_id.erase());
- w!(self, "extern ");
- if let Some(abi) = abi {
- w!(self, "\"{}\" ", abi);
- }
- w!(self, "{{");
+ w!(self, "extern {{");
self.indented(|this| {
for child in &**children {
this.print_mod_item(*child);
@@ -235,11 +199,11 @@ impl Printer<'_> {
wln!(self, "fn {};", name.display(self.db, self.edition));
}
ModItem::Struct(it) => {
- let Struct { visibility, name, fields, shape: kind, ast_id } = &self.tree[it];
+ let Struct { visibility, name, shape: kind, ast_id } = &self.tree[it];
self.print_ast_id(ast_id.erase());
self.print_visibility(*visibility);
w!(self, "struct {}", name.display(self.db, self.edition));
- self.print_fields(FieldParent::Struct(it), *kind, fields);
+ self.print_fields(*kind);
if matches!(kind, FieldsShape::Record) {
wln!(self);
} else {
@@ -247,30 +211,18 @@ impl Printer<'_> {
}
}
ModItem::Union(it) => {
- let Union { name, visibility, fields, ast_id } = &self.tree[it];
+ let Union { name, visibility, ast_id } = &self.tree[it];
self.print_ast_id(ast_id.erase());
self.print_visibility(*visibility);
w!(self, "union {}", name.display(self.db, self.edition));
- self.print_fields(FieldParent::Union(it), FieldsShape::Record, fields);
+ self.print_fields(FieldsShape::Record);
wln!(self);
}
ModItem::Enum(it) => {
- let Enum { name, visibility, variants, ast_id } = &self.tree[it];
+ let Enum { name, visibility, ast_id } = &self.tree[it];
self.print_ast_id(ast_id.erase());
self.print_visibility(*visibility);
- w!(self, "enum {}", name.display(self.db, self.edition));
- let edition = self.edition;
- self.indented(|this| {
- for variant in FileItemTreeId::range_iter(variants.clone()) {
- let Variant { name, fields, shape: kind, ast_id } = &this.tree[variant];
- this.print_ast_id(ast_id.erase());
- this.print_attrs_of(variant, "\n");
- w!(this, "{}", name.display(self.db, edition));
- this.print_fields(FieldParent::EnumVariant(variant), *kind, fields);
- wln!(this, ",");
- }
- });
- wln!(self, "}}");
+ w!(self, "enum {} {{ ... }}", name.display(self.db, self.edition));
}
ModItem::Const(it) => {
let Const { name, visibility, ast_id } = &self.tree[it];
@@ -293,16 +245,10 @@ impl Printer<'_> {
wln!(self);
}
ModItem::Trait(it) => {
- let Trait { name, visibility, items, ast_id } = &self.tree[it];
+ let Trait { name, visibility, ast_id } = &self.tree[it];
self.print_ast_id(ast_id.erase());
self.print_visibility(*visibility);
- w!(self, "trait {} {{", name.display(self.db, self.edition));
- self.indented(|this| {
- for item in &**items {
- this.print_mod_item((*item).into());
- }
- });
- wln!(self, "}}");
+ w!(self, "trait {} {{ ... }}", name.display(self.db, self.edition));
}
ModItem::TraitAlias(it) => {
let TraitAlias { name, visibility, ast_id } = &self.tree[it];
@@ -311,15 +257,9 @@ impl Printer<'_> {
wln!(self, "trait {} = ..;", name.display(self.db, self.edition));
}
ModItem::Impl(it) => {
- let Impl { items, ast_id } = &self.tree[it];
+ let Impl { ast_id } = &self.tree[it];
self.print_ast_id(ast_id.erase());
- w!(self, "impl {{");
- self.indented(|this| {
- for item in &**items {
- this.print_mod_item((*item).into());
- }
- });
- wln!(self, "}}");
+ w!(self, "impl {{ ... }}");
}
ModItem::TypeAlias(it) => {
let TypeAlias { name, visibility, ast_id } = &self.tree[it];
@@ -353,8 +293,8 @@ impl Printer<'_> {
let MacroCall { path, ast_id, expand_to, ctxt } = &self.tree[it];
let _ = writeln!(
self,
- "// AstId: {:?}, SyntaxContextId: {}, ExpandTo: {:?}",
- ast_id.erase().into_raw(),
+ "// AstId: {:#?}, SyntaxContextId: {}, ExpandTo: {:?}",
+ ast_id.erase(),
ctxt,
expand_to
);
@@ -377,7 +317,7 @@ impl Printer<'_> {
}
fn print_ast_id(&mut self, ast_id: ErasedFileAstId) {
- wln!(self, "// AstId: {:?}", ast_id.into_raw());
+ wln!(self, "// AstId: {ast_id:#?}");
}
}
diff --git a/crates/hir-def/src/item_tree/tests.rs b/crates/hir-def/src/item_tree/tests.rs
index 824fbfa592..e39efd31c6 100644
--- a/crates/hir-def/src/item_tree/tests.rs
+++ b/crates/hir-def/src/item_tree/tests.rs
@@ -35,23 +35,23 @@ use a::{c, d::{e}};
#![no_std]
#![doc = " another file comment"]
- // AstId: 1
+ // AstId: ExternCrate[5A82, 0]
pub(self) extern crate self as renamed;
- // AstId: 2
+ // AstId: ExternCrate[7E1C, 0]
pub(super) extern crate bli;
- // AstId: 3
+ // AstId: Use[0000, 0]
pub use crate::path::{nested, items as renamed, Trait as _};
- // AstId: 4
+ // AstId: Use[0000, 1]
pub(self) use globs::*;
#[doc = " docs on import"]
- // AstId: 5
+ // AstId: Use[0000, 2]
pub(self) use crate::{A, B};
- // AstId: 6
+ // AstId: Use[0000, 3]
pub(self) use a::{c, d::{e}};
"##]],
);
@@ -73,23 +73,23 @@ extern "C" {
fn ex_fn();
}
"#,
- expect![[r##"
+ expect![[r#"
#[on_extern_block]
- // AstId: 1
- extern "C" {
+ // AstId: ExternBlock[0000, 0]
+ extern {
#[on_extern_type]
- // AstId: 2
+ // AstId: TypeAlias[9FDF, 0]
pub(self) type ExType;
#[on_extern_static]
- // AstId: 3
+ // AstId: Static[43C1, 0]
pub(self) static EX_STATIC = _;
#[on_extern_fn]
- // AstId: 4
+ // AstId: Fn[452D, 0]
pub(self) fn ex_fn;
}
- "##]],
+ "#]],
);
}
@@ -124,44 +124,21 @@ enum E {
}
"#,
expect![[r#"
- // AstId: 1
+ // AstId: Struct[DFF3, 0]
pub(self) struct Unit;
#[derive(Debug)]
- // AstId: 2
- pub(self) struct Struct {
- #[doc = " fld docs"]
- pub(self) fld,
- }
+ // AstId: Struct[C7A1, 0]
+ pub(self) struct Struct { ... }
- // AstId: 3
- pub(self) struct Tuple(
- #[attr]
- pub(self) 0,
- );
+ // AstId: Struct[DAC2, 0]
+ pub(self) struct Tuple(...);
- // AstId: 4
- pub(self) union Ize {
- pub(self) a,
- pub(self) b,
- }
+ // AstId: Union[2DBB, 0]
+ pub(self) union Ize { ... }
- // AstId: 5
- pub(self) enum E
- // AstId: 6
- #[doc = " comment on Unit"]
- Unit,
- // AstId: 7
- #[doc = " comment on Tuple"]
- Tuple(
- pub(self) 0,
- ),
- // AstId: 8
- Struct {
- #[doc = " comment on a: u8"]
- pub(self) a,
- },
- }
+ // AstId: Enum[7FF8, 0]
+ pub(self) enum E { ... }
"#]],
);
}
@@ -185,25 +162,19 @@ trait Tr: SuperTrait + 'lifetime {
}
"#,
expect![[r#"
- // AstId: 1
+ // AstId: Static[B393, 0]
pub static ST = _;
- // AstId: 2
+ // AstId: Const[B309, 0]
pub(self) const _ = _;
#[attr]
#[inner_attr_in_fn]
- // AstId: 3
+ // AstId: Fn[75E3, 0]
pub(self) fn f;
- // AstId: 4
- pub(self) trait Tr {
- // AstId: 6
- pub(self) type Assoc;
-
- // AstId: 7
- pub(self) fn method;
- }
+ // AstId: Trait[2998, 0]
+ pub(self) trait Tr { ... }
"#]],
);
}
@@ -226,16 +197,16 @@ mod outline;
expect![[r##"
#[doc = " outer"]
#[doc = " inner"]
- // AstId: 1
+ // AstId: Module[CF93, 0]
pub(self) mod inline {
- // AstId: 3
+ // AstId: Use[0000, 0]
pub(self) use super::*;
- // AstId: 4
+ // AstId: Fn[1B26, 0]
pub(self) fn fn_in_module;
}
- // AstId: 2
+ // AstId: Module[8994, 0]
pub(self) mod outline;
"##]],
);
@@ -254,13 +225,13 @@ pub macro m2() {}
m!();
"#,
expect![[r#"
- // AstId: 1
+ // AstId: MacroRules[88CE, 0]
macro_rules! m { ... }
- // AstId: 2
+ // AstId: MacroDef[DC34, 0]
pub macro m2 { ... }
- // AstId: 3, SyntaxContextId: ROOT2024, ExpandTo: Items
+ // AstId: MacroCall[612F, 0], SyntaxContextId: ROOT2024, ExpandTo: Items
m!(...);
"#]],
);
@@ -273,7 +244,7 @@ fn pub_self() {
pub(self) struct S;
"#,
expect![[r#"
- // AstId: 1
+ // AstId: Struct[42E2, 0]
pub(self) struct S;
"#]],
)
diff --git a/crates/hir-def/src/lang_item.rs b/crates/hir-def/src/lang_item.rs
index 4ad44775ea..1614ef0da4 100644
--- a/crates/hir-def/src/lang_item.rs
+++ b/crates/hir-def/src/lang_item.rs
@@ -125,7 +125,7 @@ pub fn crate_lang_items(db: &dyn DefDatabase, krate: Crate) -> Option<Box<LangIt
}
ModuleDefId::AdtId(AdtId::EnumId(e)) => {
lang_items.collect_lang_item(db, e, LangItemTarget::EnumId);
- db.enum_variants(e).variants.iter().for_each(|&(id, _)| {
+ db.enum_variants(e).variants.iter().for_each(|&(id, _, _)| {
lang_items.collect_lang_item(db, id, LangItemTarget::EnumVariant);
});
}
diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs
index 1e8859a9cc..dcc18666a5 100644
--- a/crates/hir-def/src/lib.rs
+++ b/crates/hir-def/src/lib.rs
@@ -74,12 +74,11 @@ use hir_expand::{
name::Name,
proc_macro::{CustomProcMacroExpander, ProcMacroKind},
};
-use item_tree::ExternBlock;
use la_arena::Idx;
use nameres::DefMap;
use span::{AstIdNode, Edition, FileAstId, SyntaxContext};
use stdx::impl_from;
-use syntax::ast;
+use syntax::{AstNode, ast};
pub use hir_expand::{Intern, Lookup, tt};
@@ -88,10 +87,6 @@ use crate::{
builtin_type::BuiltinType,
db::DefDatabase,
hir::generics::{LocalLifetimeParamId, LocalTypeOrConstParamId},
- item_tree::{
- Const, Enum, ExternCrate, Function, Impl, ItemTreeId, ItemTreeNode, Macro2, MacroRules,
- Static, Struct, Trait, TraitAlias, TypeAlias, Union, Use, Variant,
- },
nameres::{LocalDefMap, block_def_map, crate_def_map, crate_local_def_map},
signatures::VariantFields,
};
@@ -113,70 +108,110 @@ pub struct ImportPathConfig {
}
#[derive(Debug)]
-pub struct ItemLoc<N: ItemTreeNode> {
+pub struct ItemLoc<N: AstIdNode> {
pub container: ModuleId,
- pub id: ItemTreeId<N>,
+ pub id: AstId<N>,
}
-impl<N: ItemTreeNode> Clone for ItemLoc<N> {
+impl<N: AstIdNode> Clone for ItemLoc<N> {
fn clone(&self) -> Self {
*self
}
}
-impl<N: ItemTreeNode> Copy for ItemLoc<N> {}
+impl<N: AstIdNode> Copy for ItemLoc<N> {}
-impl<N: ItemTreeNode> PartialEq for ItemLoc<N> {
+impl<N: AstIdNode> 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: AstIdNode> Eq for ItemLoc<N> {}
-impl<N: ItemTreeNode> Hash for ItemLoc<N> {
+impl<N: AstIdNode> Hash for ItemLoc<N> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.container.hash(state);
self.id.hash(state);
}
}
+impl<N: AstIdNode> HasModule for ItemLoc<N> {
+ #[inline]
+ fn module(&self, _db: &dyn DefDatabase) -> ModuleId {
+ self.container
+ }
+}
+
#[derive(Debug)]
-pub struct AssocItemLoc<N: ItemTreeNode> {
+pub struct AssocItemLoc<N: AstIdNode> {
pub container: ItemContainerId,
- pub id: ItemTreeId<N>,
+ pub id: AstId<N>,
}
-impl<N: ItemTreeNode> Clone for AssocItemLoc<N> {
+impl<N: AstIdNode> Clone for AssocItemLoc<N> {
fn clone(&self) -> Self {
*self
}
}
-impl<N: ItemTreeNode> Copy for AssocItemLoc<N> {}
+impl<N: AstIdNode> Copy for AssocItemLoc<N> {}
-impl<N: ItemTreeNode> PartialEq for AssocItemLoc<N> {
+impl<N: AstIdNode> 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: AstIdNode> Eq for AssocItemLoc<N> {}
-impl<N: ItemTreeNode> Hash for AssocItemLoc<N> {
+impl<N: AstIdNode> Hash for AssocItemLoc<N> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.container.hash(state);
self.id.hash(state);
}
}
-pub trait ItemTreeLoc {
+impl<N: AstIdNode> HasModule for AssocItemLoc<N> {
+ #[inline]
+ fn module(&self, db: &dyn DefDatabase) -> ModuleId {
+ self.container.module(db)
+ }
+}
+
+pub trait AstIdLoc {
type Container;
- type Id;
- fn item_tree_id(&self) -> ItemTreeId<Self::Id>;
+ type Ast: AstNode;
+ fn ast_id(&self) -> AstId<Self::Ast>;
fn container(&self) -> Self::Container;
}
+impl<N: AstIdNode> AstIdLoc for ItemLoc<N> {
+ type Container = ModuleId;
+ type Ast = N;
+ #[inline]
+ fn ast_id(&self) -> AstId<Self::Ast> {
+ self.id
+ }
+ #[inline]
+ fn container(&self) -> Self::Container {
+ self.container
+ }
+}
+
+impl<N: AstIdNode> AstIdLoc for AssocItemLoc<N> {
+ type Container = ItemContainerId;
+ type Ast = N;
+ #[inline]
+ fn ast_id(&self) -> AstId<Self::Ast> {
+ self.id
+ }
+ #[inline]
+ fn container(&self) -> Self::Container {
+ self.container
+ }
+}
+
macro_rules! impl_intern {
($id:ident, $loc:ident, $intern:ident, $lookup:ident) => {
impl_intern_key!($id, $loc);
@@ -186,74 +221,68 @@ macro_rules! impl_intern {
macro_rules! impl_loc {
($loc:ident, $id:ident: $id_ty:ident, $container:ident: $container_type:ident) => {
- impl ItemTreeLoc for $loc {
+ impl AstIdLoc for $loc {
type Container = $container_type;
- type Id = $id_ty;
- fn item_tree_id(&self) -> ItemTreeId<Self::Id> {
+ type Ast = ast::$id_ty;
+ fn ast_id(&self) -> AstId<Self::Ast> {
self.$id
}
fn container(&self) -> Self::Container {
self.$container
}
}
+
+ impl HasModule for $loc {
+ #[inline]
+ fn module(&self, db: &dyn DefDatabase) -> ModuleId {
+ self.$container.module(db)
+ }
+ }
};
}
-type FunctionLoc = AssocItemLoc<Function>;
+type FunctionLoc = AssocItemLoc<ast::Fn>;
impl_intern!(FunctionId, FunctionLoc, intern_function, lookup_intern_function);
-impl_loc!(FunctionLoc, id: Function, container: ItemContainerId);
-type StructLoc = ItemLoc<Struct>;
+type StructLoc = ItemLoc<ast::Struct>;
impl_intern!(StructId, StructLoc, intern_struct, lookup_intern_struct);
-impl_loc!(StructLoc, id: Struct, container: ModuleId);
-pub type UnionLoc = ItemLoc<Union>;
+pub type UnionLoc = ItemLoc<ast::Union>;
impl_intern!(UnionId, UnionLoc, intern_union, lookup_intern_union);
-impl_loc!(UnionLoc, id: Union, container: ModuleId);
-pub type EnumLoc = ItemLoc<Enum>;
+pub type EnumLoc = ItemLoc<ast::Enum>;
impl_intern!(EnumId, EnumLoc, intern_enum, lookup_intern_enum);
-impl_loc!(EnumLoc, id: Enum, container: ModuleId);
-type ConstLoc = AssocItemLoc<Const>;
+type ConstLoc = AssocItemLoc<ast::Const>;
impl_intern!(ConstId, ConstLoc, intern_const, lookup_intern_const);
-impl_loc!(ConstLoc, id: Const, container: ItemContainerId);
-pub type StaticLoc = AssocItemLoc<Static>;
+pub type StaticLoc = AssocItemLoc<ast::Static>;
impl_intern!(StaticId, StaticLoc, intern_static, lookup_intern_static);
-impl_loc!(StaticLoc, id: Static, container: ItemContainerId);
-pub type TraitLoc = ItemLoc<Trait>;
+pub type TraitLoc = ItemLoc<ast::Trait>;
impl_intern!(TraitId, TraitLoc, intern_trait, lookup_intern_trait);
-impl_loc!(TraitLoc, id: Trait, container: ModuleId);
-pub type TraitAliasLoc = ItemLoc<TraitAlias>;
+pub type TraitAliasLoc = ItemLoc<ast::TraitAlias>;
impl_intern!(TraitAliasId, TraitAliasLoc, intern_trait_alias, lookup_intern_trait_alias);
-impl_loc!(TraitAliasLoc, id: TraitAlias, container: ModuleId);
-type TypeAliasLoc = AssocItemLoc<TypeAlias>;
+type TypeAliasLoc = AssocItemLoc<ast::TypeAlias>;
impl_intern!(TypeAliasId, TypeAliasLoc, intern_type_alias, lookup_intern_type_alias);
-impl_loc!(TypeAliasLoc, id: TypeAlias, container: ItemContainerId);
-type ImplLoc = ItemLoc<Impl>;
+type ImplLoc = ItemLoc<ast::Impl>;
impl_intern!(ImplId, ImplLoc, intern_impl, lookup_intern_impl);
-impl_loc!(ImplLoc, id: Impl, container: ModuleId);
-type UseLoc = ItemLoc<Use>;
+type UseLoc = ItemLoc<ast::Use>;
impl_intern!(UseId, UseLoc, intern_use, lookup_intern_use);
-impl_loc!(UseLoc, id: Use, container: ModuleId);
-type ExternCrateLoc = ItemLoc<ExternCrate>;
+type ExternCrateLoc = ItemLoc<ast::ExternCrate>;
impl_intern!(ExternCrateId, ExternCrateLoc, intern_extern_crate, lookup_intern_extern_crate);
-impl_loc!(ExternCrateLoc, id: ExternCrate, container: ModuleId);
-type ExternBlockLoc = ItemLoc<ExternBlock>;
+type ExternBlockLoc = ItemLoc<ast::ExternBlock>;
impl_intern!(ExternBlockId, ExternBlockLoc, intern_extern_block, lookup_intern_extern_block);
-impl_loc!(ExternBlockLoc, id: ExternBlock, container: ModuleId);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct EnumVariantLoc {
- pub id: ItemTreeId<Variant>,
+ pub id: AstId<ast::Variant>,
pub parent: EnumId,
pub index: u32,
}
@@ -262,18 +291,18 @@ impl_loc!(EnumVariantLoc, id: Variant, parent: EnumId);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Macro2Loc {
pub container: ModuleId,
- pub id: ItemTreeId<Macro2>,
+ pub id: AstId<ast::MacroDef>,
pub expander: MacroExpander,
pub allow_internal_unsafe: bool,
pub edition: Edition,
}
impl_intern!(Macro2Id, Macro2Loc, intern_macro2, lookup_intern_macro2);
-impl_loc!(Macro2Loc, id: Macro2, container: ModuleId);
+impl_loc!(Macro2Loc, id: MacroDef, container: ModuleId);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MacroRulesLoc {
pub container: ModuleId,
- pub id: ItemTreeId<MacroRules>,
+ pub id: AstId<ast::MacroRules>,
pub expander: MacroExpander,
pub flags: MacroRulesLocFlags,
pub edition: Edition,
@@ -301,13 +330,13 @@ pub enum MacroExpander {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ProcMacroLoc {
pub container: CrateRootModuleId,
- pub id: ItemTreeId<Function>,
+ pub id: AstId<ast::Fn>,
pub expander: CustomProcMacroExpander,
pub kind: ProcMacroKind,
pub edition: Edition,
}
impl_intern!(ProcMacroId, ProcMacroLoc, intern_proc_macro, lookup_intern_proc_macro);
-impl_loc!(ProcMacroLoc, id: Function, container: CrateRootModuleId);
+impl_loc!(ProcMacroLoc, id: Fn, container: CrateRootModuleId);
#[derive(Debug, Hash, PartialEq, Eq, Clone)]
pub struct BlockLoc {
@@ -338,6 +367,18 @@ impl CrateRootModuleId {
}
}
+impl HasModule for CrateRootModuleId {
+ #[inline]
+ fn module(&self, _db: &dyn DefDatabase) -> ModuleId {
+ ModuleId { krate: self.krate, block: None, local_id: DefMap::ROOT }
+ }
+
+ #[inline]
+ fn krate(&self, _db: &dyn DefDatabase) -> Crate {
+ self.krate
+ }
+}
+
impl PartialEq<ModuleId> for CrateRootModuleId {
fn eq(&self, other: &ModuleId) -> bool {
other.block.is_none() && other.local_id == DefMap::ROOT && self.krate == other.krate
@@ -466,6 +507,13 @@ impl ModuleId {
}
}
+impl HasModule for ModuleId {
+ #[inline]
+ fn module(&self, _db: &dyn DefDatabase) -> ModuleId {
+ *self
+ }
+}
+
/// An ID of a module, **local** to a `DefMap`.
pub type LocalModuleId = Idx<nameres::ModuleData>;
@@ -642,15 +690,10 @@ impl GeneralConstId {
pub fn name(self, db: &dyn DefDatabase) -> String {
match self {
GeneralConstId::StaticId(it) => {
- let loc = it.lookup(db);
- let tree = loc.item_tree_id().item_tree(db);
- let name = tree[loc.id.value].name.display(db, Edition::CURRENT);
- name.to_string()
+ db.static_signature(it).name.display(db, Edition::CURRENT).to_string()
}
GeneralConstId::ConstId(const_id) => {
- let loc = const_id.lookup(db);
- let tree = loc.item_tree_id().item_tree(db);
- tree[loc.id.value].name.as_ref().map_or_else(
+ db.const_signature(const_id).name.as_ref().map_or_else(
|| "_".to_owned(),
|name| name.display(db, Edition::CURRENT).to_string(),
)
@@ -768,8 +811,8 @@ impl GenericDefId {
GenericDefId::TraitId(it) => file_id_and_params_of_item_loc(db, it),
GenericDefId::TraitAliasId(it) => file_id_and_params_of_item_loc(db, it),
GenericDefId::ImplId(it) => file_id_and_params_of_item_loc(db, it),
- GenericDefId::ConstId(it) => (it.lookup(db).id.file_id(), None),
- GenericDefId::StaticId(it) => (it.lookup(db).id.file_id(), None),
+ GenericDefId::ConstId(it) => (it.lookup(db).id.file_id, None),
+ GenericDefId::StaticId(it) => (it.lookup(db).id.file_id, None),
}
}
@@ -935,9 +978,9 @@ impl VariantId {
pub fn file_id(self, db: &dyn DefDatabase) -> HirFileId {
match self {
- 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(),
+ 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,
}
}
@@ -977,7 +1020,7 @@ pub trait HasModule {
impl<N, ItemId> HasModule for ItemId
where
- N: ItemTreeNode,
+ N: AstIdNode,
ItemId: Lookup<Database = dyn DefDatabase, Data = ItemLoc<N>> + Copy,
{
#[inline]
@@ -1003,7 +1046,7 @@ where
#[inline]
fn module_for_assoc_item_loc<'db>(
db: &(dyn 'db + DefDatabase),
- id: impl Lookup<Database = dyn DefDatabase, Data = AssocItemLoc<impl ItemTreeNode>>,
+ id: impl Lookup<Database = dyn DefDatabase, Data = AssocItemLoc<impl AstIdNode>>,
) -> ModuleId {
id.lookup(db).container.module(db)
}
diff --git a/crates/hir-def/src/macro_expansion_tests/mbe.rs b/crates/hir-def/src/macro_expansion_tests/mbe.rs
index 38fc4b3d11..eea50d16f5 100644
--- a/crates/hir-def/src/macro_expansion_tests/mbe.rs
+++ b/crates/hir-def/src/macro_expansion_tests/mbe.rs
@@ -35,9 +35,9 @@ macro_rules! f {
};
}
-struct#0:[email protected]#14336# MyTraitMap2#0:[email protected]#ROOT2024# {#0:[email protected]#14336#
- map#0:[email protected]#14336#:#0:[email protected]#14336# #0:[email protected]#14336#::#0:[email protected]#14336#std#0:[email protected]#14336#::#0:[email protected]#14336#collections#0:[email protected]#14336#::#0:[email protected]#14336#HashSet#0:[email protected]#14336#<#0:[email protected]#14336#(#0:[email protected]#14336#)#0:[email protected]#14336#>#0:[email protected]#14336#,#0:[email protected]#14336#
-}#0:[email protected]#14336#
+struct#0:MacroRules[8C8E, 0]@58..64#14336# MyTraitMap2#0:MacroCall[D499, 0]@31..42#ROOT2024# {#0:MacroRules[8C8E, 0]@72..73#14336#
+ map#0:MacroRules[8C8E, 0]@86..89#14336#:#0:MacroRules[8C8E, 0]@89..90#14336# #0:MacroRules[8C8E, 0]@89..90#14336#::#0:MacroRules[8C8E, 0]@91..93#14336#std#0:MacroRules[8C8E, 0]@93..96#14336#::#0:MacroRules[8C8E, 0]@96..98#14336#collections#0:MacroRules[8C8E, 0]@98..109#14336#::#0:MacroRules[8C8E, 0]@109..111#14336#HashSet#0:MacroRules[8C8E, 0]@111..118#14336#<#0:MacroRules[8C8E, 0]@118..119#14336#(#0:MacroRules[8C8E, 0]@119..120#14336#)#0:MacroRules[8C8E, 0]@120..121#14336#>#0:MacroRules[8C8E, 0]@121..122#14336#,#0:MacroRules[8C8E, 0]@122..123#14336#
+}#0:MacroRules[8C8E, 0]@132..133#14336#
"#]],
);
}
@@ -75,12 +75,12 @@ macro_rules! f {
};
}
-fn#0:[email protected]#ROOT2024# main#0:[email protected]#ROOT2024#(#0:[email protected]#ROOT2024#)#0:[email protected]#ROOT2024# {#0:[email protected]#ROOT2024#
- 1#0:[email protected]#ROOT2024#;#0:[email protected]#ROOT2024#
- 1.0#0:[email protected]#ROOT2024#;#0:[email protected]#ROOT2024#
- (#0:[email protected]#ROOT2024#(#0:[email protected]#ROOT2024#1#0:[email protected]#ROOT2024#,#0:[email protected]#ROOT2024# )#0:[email protected]#ROOT2024#,#0:[email protected]#ROOT2024# )#0:[email protected]#ROOT2024#.#0:[email protected]#ROOT2024#0#0:[email protected]#ROOT2024#.#0:[email protected]#ROOT2024#0#0:[email protected]#ROOT2024#;#0:[email protected]#ROOT2024#
- let#0:[email protected]#ROOT2024# x#0:[email protected]#ROOT2024# =#0:[email protected]#ROOT2024# 1#0:[email protected]#ROOT2024#;#0:[email protected]#ROOT2024#
-}#0:[email protected]#ROOT2024#
+fn#0:MacroCall[D499, 0]@30..32#ROOT2024# main#0:MacroCall[D499, 0]@33..37#ROOT2024#(#0:MacroCall[D499, 0]@37..38#ROOT2024#)#0:MacroCall[D499, 0]@38..39#ROOT2024# {#0:MacroCall[D499, 0]@40..41#ROOT2024#
+ 1#0:MacroCall[D499, 0]@50..51#ROOT2024#;#0:MacroCall[D499, 0]@51..52#ROOT2024#
+ 1.0#0:MacroCall[D499, 0]@61..64#ROOT2024#;#0:MacroCall[D499, 0]@64..65#ROOT2024#
+ (#0:MacroCall[D499, 0]@74..75#ROOT2024#(#0:MacroCall[D499, 0]@75..76#ROOT2024#1#0:MacroCall[D499, 0]@76..77#ROOT2024#,#0:MacroCall[D499, 0]@77..78#ROOT2024# )#0:MacroCall[D499, 0]@78..79#ROOT2024#,#0:MacroCall[D499, 0]@79..80#ROOT2024# )#0:MacroCall[D499, 0]@80..81#ROOT2024#.#0:MacroCall[D499, 0]@81..82#ROOT2024#0#0:MacroCall[D499, 0]@82..85#ROOT2024#.#0:MacroCall[D499, 0]@82..85#ROOT2024#0#0:MacroCall[D499, 0]@82..85#ROOT2024#;#0:MacroCall[D499, 0]@85..86#ROOT2024#
+ let#0:MacroCall[D499, 0]@95..98#ROOT2024# x#0:MacroCall[D499, 0]@99..100#ROOT2024# =#0:MacroCall[D499, 0]@101..102#ROOT2024# 1#0:MacroCall[D499, 0]@103..104#ROOT2024#;#0:MacroCall[D499, 0]@104..105#ROOT2024#
+}#0:MacroCall[D499, 0]@110..111#ROOT2024#
"#]],
@@ -171,7 +171,7 @@ fn main(foo: ()) {
}
fn main(foo: ()) {
- /* error: unresolved macro unresolved */"helloworld!"#0:[email protected]#ROOT2024#;
+ /* error: unresolved macro unresolved */"helloworld!"#0:Fn[B9C7, 0]@236..321#ROOT2024#;
}
}
@@ -197,7 +197,7 @@ macro_rules! mk_struct {
#[macro_use]
mod foo;
-struct#1:[email protected]#14336# Foo#0:[email protected]#ROOT2024#(#1:[email protected]#14336#u32#0:[email protected]#ROOT2024#)#1:[email protected]#14336#;#1:[email protected]#14336#
+struct#1:MacroRules[E572, 0]@59..65#14336# Foo#0:MacroCall[BDD3, 0]@32..35#ROOT2024#(#1:MacroRules[E572, 0]@70..71#14336#u32#0:MacroCall[BDD3, 0]@41..44#ROOT2024#)#1:MacroRules[E572, 0]@74..75#14336#;#1:MacroRules[E572, 0]@75..76#14336#
"#]],
);
}
diff --git a/crates/hir-def/src/macro_expansion_tests/proc_macros.rs b/crates/hir-def/src/macro_expansion_tests/proc_macros.rs
index b2e1adc365..d5ae6f8d88 100644
--- a/crates/hir-def/src/macro_expansion_tests/proc_macros.rs
+++ b/crates/hir-def/src/macro_expansion_tests/proc_macros.rs
@@ -181,9 +181,9 @@ fn foo(&self) {
self.0. 1;
}
-fn#0:[email protected]#ROOT2024# foo#0:[email protected]#ROOT2024#(#0:[email protected]#ROOT2024#&#0:[email protected]#ROOT2024#self#0:[email protected]#ROOT2024# )#0:[email protected]#ROOT2024# {#0:[email protected]#ROOT2024#
- self#0:[email protected]#ROOT2024# .#0:[email protected]#ROOT2024#0#0:[email protected]#ROOT2024#.#0:[email protected]#ROOT2024#1#0:[email protected]#ROOT2024#;#0:[email protected]#ROOT2024#
-}#0:[email protected]#ROOT2024#"#]],
+fn#0:Fn[4D85, 0]@45..47#ROOT2024# foo#0:Fn[4D85, 0]@48..51#ROOT2024#(#0:Fn[4D85, 0]@51..52#ROOT2024#&#0:Fn[4D85, 0]@52..53#ROOT2024#self#0:Fn[4D85, 0]@53..57#ROOT2024# )#0:Fn[4D85, 0]@57..58#ROOT2024# {#0:Fn[4D85, 0]@59..60#ROOT2024#
+ self#0:Fn[4D85, 0]@65..69#ROOT2024# .#0:Fn[4D85, 0]@69..70#ROOT2024#0#0:Fn[4D85, 0]@70..71#ROOT2024#.#0:Fn[4D85, 0]@71..72#ROOT2024#1#0:Fn[4D85, 0]@73..74#ROOT2024#;#0:Fn[4D85, 0]@74..75#ROOT2024#
+}#0:Fn[4D85, 0]@76..77#ROOT2024#"#]],
);
}
diff --git a/crates/hir-def/src/nameres.rs b/crates/hir-def/src/nameres.rs
index f337f83156..c908e45754 100644
--- a/crates/hir-def/src/nameres.rs
+++ b/crates/hir-def/src/nameres.rs
@@ -171,12 +171,10 @@ pub struct DefMap {
/// ExternCrateId being None implies it being imported from the general prelude import.
macro_use_prelude: FxHashMap<Name, (MacroId, Option<ExternCrateId>)>,
- // FIXME: AstId's are fairly unstable
/// Tracks which custom derives are in scope for an item, to allow resolution of derive helper
/// attributes.
// FIXME: Figure out a better way for the IDE layer to resolve these?
derive_helpers_in_scope: FxHashMap<AstId<ast::Item>, Vec<(Name, MacroId, MacroCallId)>>,
- // FIXME: AstId's are fairly unstable
/// A mapping from [`hir_expand::MacroDefId`] to [`crate::MacroId`].
pub macro_def_to_macro_id: FxHashMap<ErasedAstId, MacroId>,
diff --git a/crates/hir-def/src/nameres/assoc.rs b/crates/hir-def/src/nameres/assoc.rs
index 86225d33b4..cf123d14f5 100644
--- a/crates/hir-def/src/nameres/assoc.rs
+++ b/crates/hir-def/src/nameres/assoc.rs
@@ -1,14 +1,28 @@
//! Expansion of associated items
-use hir_expand::{AstId, InFile, Intern, Lookup, MacroCallKind, MacroDefKind, name::Name};
-use syntax::ast;
+use std::mem;
+
+use cfg::CfgOptions;
+use hir_expand::{
+ AstId, ExpandTo, HirFileId, InFile, Intern, Lookup, MacroCallKind, MacroDefKind,
+ mod_path::ModPath,
+ name::{AsName, Name},
+ span_map::SpanMap,
+};
+use intern::Interned;
+use span::AstIdMap;
+use syntax::{
+ AstNode,
+ ast::{self, HasModuleItem, HasName},
+};
+use thin_vec::ThinVec;
use triomphe::Arc;
use crate::{
AssocItemId, AstIdWithPath, ConstLoc, FunctionId, FunctionLoc, ImplId, ItemContainerId,
ItemLoc, MacroCallId, ModuleId, TraitId, TypeAliasId, TypeAliasLoc,
+ attr::Attrs,
db::DefDatabase,
- item_tree::{AssocItem, ItemTree, ItemTreeId, MacroCall, ModItem, TreeId},
macro_call_as_call_id,
nameres::{
DefMap, LocalDefMap, MacroSubNs,
@@ -20,9 +34,8 @@ use crate::{
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TraitItems {
pub items: Box<[(Name, AssocItemId)]>,
- // box it as the vec is usually empty anyways
- // FIXME: AstIds are rather unstable...
- pub macro_calls: Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>,
+ // `ThinVec` as the vec is usually empty anyways
+ pub macro_calls: ThinVec<(AstId<ast::Item>, MacroCallId)>,
}
impl TraitItems {
@@ -35,12 +48,12 @@ impl TraitItems {
db: &dyn DefDatabase,
tr: TraitId,
) -> (Arc<TraitItems>, DefDiagnostics) {
- let ItemLoc { container: module_id, id: tree_id } = tr.lookup(db);
+ let ItemLoc { container: module_id, id: ast_id } = tr.lookup(db);
- let collector = AssocItemCollector::new(db, module_id, ItemContainerId::TraitId(tr));
- let item_tree = tree_id.item_tree(db);
- let (items, macro_calls, diagnostics) =
- collector.collect(&item_tree, tree_id.tree_id(), &item_tree[tree_id.value].items);
+ let collector =
+ AssocItemCollector::new(db, module_id, ItemContainerId::TraitId(tr), ast_id.file_id);
+ let source = ast_id.with_value(collector.ast_id_map.get(ast_id.value)).to_node(db);
+ let (items, macro_calls, diagnostics) = collector.collect(source.assoc_item_list());
(Arc::new(TraitItems { macro_calls, items }), DefDiagnostics::new(diagnostics))
}
@@ -76,16 +89,15 @@ impl TraitItems {
}
pub fn macro_calls(&self) -> impl Iterator<Item = (AstId<ast::Item>, MacroCallId)> + '_ {
- self.macro_calls.iter().flat_map(|it| it.iter()).copied()
+ self.macro_calls.iter().copied()
}
}
#[derive(Debug, PartialEq, Eq)]
pub struct ImplItems {
pub items: Box<[(Name, AssocItemId)]>,
- // box it as the vec is usually empty anyways
- // FIXME: AstIds are rather unstable...
- pub macro_calls: Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>,
+ // `ThinVec` as the vec is usually empty anyways
+ pub macro_calls: ThinVec<(AstId<ast::Item>, MacroCallId)>,
}
impl ImplItems {
@@ -99,18 +111,18 @@ impl ImplItems {
id: ImplId,
) -> (Arc<ImplItems>, DefDiagnostics) {
let _p = tracing::info_span!("impl_items_with_diagnostics_query").entered();
- let ItemLoc { container: module_id, id: tree_id } = id.lookup(db);
+ let ItemLoc { container: module_id, id: ast_id } = id.lookup(db);
- let collector = AssocItemCollector::new(db, module_id, ItemContainerId::ImplId(id));
- let item_tree = tree_id.item_tree(db);
- let (items, macro_calls, diagnostics) =
- collector.collect(&item_tree, tree_id.tree_id(), &item_tree[tree_id.value].items);
+ let collector =
+ AssocItemCollector::new(db, module_id, ItemContainerId::ImplId(id), ast_id.file_id);
+ let source = ast_id.with_value(collector.ast_id_map.get(ast_id.value)).to_node(db);
+ let (items, macro_calls, diagnostics) = collector.collect(source.assoc_item_list());
(Arc::new(ImplItems { items, macro_calls }), DefDiagnostics::new(diagnostics))
}
pub fn macro_calls(&self) -> impl Iterator<Item = (AstId<ast::Item>, MacroCallId)> + '_ {
- self.macro_calls.iter().flat_map(|it| it.iter()).copied()
+ self.macro_calls.iter().copied()
}
}
@@ -119,67 +131,73 @@ struct AssocItemCollector<'a> {
module_id: ModuleId,
def_map: &'a DefMap,
local_def_map: &'a LocalDefMap,
+ ast_id_map: Arc<AstIdMap>,
+ span_map: SpanMap,
+ cfg_options: &'a CfgOptions,
+ file_id: HirFileId,
diagnostics: Vec<DefDiagnostic>,
container: ItemContainerId,
depth: usize,
items: Vec<(Name, AssocItemId)>,
- macro_calls: Vec<(AstId<ast::Item>, MacroCallId)>,
+ macro_calls: ThinVec<(AstId<ast::Item>, MacroCallId)>,
}
impl<'a> AssocItemCollector<'a> {
- fn new(db: &'a dyn DefDatabase, module_id: ModuleId, container: ItemContainerId) -> Self {
+ fn new(
+ db: &'a dyn DefDatabase,
+ module_id: ModuleId,
+ container: ItemContainerId,
+ file_id: HirFileId,
+ ) -> Self {
let (def_map, local_def_map) = module_id.local_def_map(db);
Self {
db,
module_id,
def_map,
local_def_map,
+ ast_id_map: db.ast_id_map(file_id),
+ span_map: db.span_map(file_id),
+ cfg_options: module_id.krate.cfg_options(db),
+ file_id,
container,
items: Vec::new(),
depth: 0,
- macro_calls: Vec::new(),
+ macro_calls: ThinVec::new(),
diagnostics: Vec::new(),
}
}
fn collect(
mut self,
- item_tree: &ItemTree,
- tree_id: TreeId,
- assoc_items: &[AssocItem],
- ) -> (
- Box<[(Name, AssocItemId)]>,
- Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>,
- Vec<DefDiagnostic>,
- ) {
- self.items.reserve(assoc_items.len());
- for &item in assoc_items {
- self.collect_item(item_tree, tree_id, item);
+ item_list: Option<ast::AssocItemList>,
+ ) -> (Box<[(Name, AssocItemId)]>, ThinVec<(AstId<ast::Item>, MacroCallId)>, Vec<DefDiagnostic>)
+ {
+ if let Some(item_list) = item_list {
+ for item in item_list.assoc_items() {
+ self.collect_item(item);
+ }
}
- (
- self.items.into_boxed_slice(),
- if self.macro_calls.is_empty() { None } else { Some(Box::new(self.macro_calls)) },
- self.diagnostics,
- )
+ self.macro_calls.shrink_to_fit();
+ (self.items.into_boxed_slice(), self.macro_calls, self.diagnostics)
}
- fn collect_item(&mut self, item_tree: &ItemTree, tree_id: TreeId, item: AssocItem) {
- let attrs = item_tree.attrs(self.db, self.module_id.krate, ModItem::from(item).into());
- if !attrs.is_cfg_enabled(self.module_id.krate.cfg_options(self.db)) {
+ fn collect_item(&mut self, item: ast::AssocItem) {
+ let ast_id = self.ast_id_map.ast_id(&item);
+ let attrs = Attrs::new(self.db, &item, self.span_map.as_ref(), self.cfg_options);
+ if let Err(cfg) = attrs.is_cfg_enabled(self.cfg_options) {
self.diagnostics.push(DefDiagnostic::unconfigured_code(
self.module_id.local_id,
- tree_id,
- ModItem::from(item).into(),
- attrs.cfg().unwrap(),
- self.module_id.krate.cfg_options(self.db).clone(),
+ InFile::new(self.file_id, ast_id.erase()),
+ cfg,
+ self.cfg_options.clone(),
));
return;
}
+ let ast_id = InFile::new(self.file_id, ast_id.upcast());
'attrs: for attr in &*attrs {
- let ast_id = AstId::new(tree_id.file_id(), item.ast_id(item_tree).upcast());
let ast_id_with_path = AstIdWithPath { path: attr.path.clone(), ast_id };
match self.def_map.resolve_attr_macro(
@@ -223,34 +241,51 @@ impl<'a> AssocItemCollector<'a> {
}
}
- self.record_item(item_tree, tree_id, item);
+ self.record_item(item);
}
- fn record_item(&mut self, item_tree: &ItemTree, tree_id: TreeId, item: AssocItem) {
+ fn record_item(&mut self, item: ast::AssocItem) {
match item {
- AssocItem::Function(id) => {
- let item = &item_tree[id];
- let def =
- FunctionLoc { container: self.container, id: ItemTreeId::new(tree_id, id) }
- .intern(self.db);
- self.items.push((item.name.clone(), def.into()));
+ ast::AssocItem::Fn(function) => {
+ let Some(name) = function.name() else { return };
+ let ast_id = self.ast_id_map.ast_id(&function);
+ let def = FunctionLoc {
+ container: self.container,
+ id: InFile::new(self.file_id, ast_id),
+ }
+ .intern(self.db);
+ self.items.push((name.as_name(), def.into()));
+ }
+ ast::AssocItem::TypeAlias(type_alias) => {
+ let Some(name) = type_alias.name() else { return };
+ let ast_id = self.ast_id_map.ast_id(&type_alias);
+ let def = TypeAliasLoc {
+ container: self.container,
+ id: InFile::new(self.file_id, ast_id),
+ }
+ .intern(self.db);
+ self.items.push((name.as_name(), def.into()));
}
- AssocItem::TypeAlias(id) => {
- let item = &item_tree[id];
+ ast::AssocItem::Const(konst) => {
+ let Some(name) = konst.name() else { return };
+ let ast_id = self.ast_id_map.ast_id(&konst);
let def =
- TypeAliasLoc { container: self.container, id: ItemTreeId::new(tree_id, id) }
+ ConstLoc { container: self.container, id: InFile::new(self.file_id, ast_id) }
.intern(self.db);
- self.items.push((item.name.clone(), def.into()));
- }
- AssocItem::Const(id) => {
- let item = &item_tree[id];
- let Some(name) = item.name.clone() else { return };
- let def = ConstLoc { container: self.container, id: ItemTreeId::new(tree_id, id) }
- .intern(self.db);
- self.items.push((name, def.into()));
+ self.items.push((name.as_name(), def.into()));
}
- AssocItem::MacroCall(call) => {
- let MacroCall { ast_id, expand_to, ctxt, ref path } = item_tree[call];
+ ast::AssocItem::MacroCall(call) => {
+ let ast_id = self.ast_id_map.ast_id(&call);
+ let ast_id = InFile::new(self.file_id, ast_id);
+ let Some(path) = call.path() else { return };
+ let range = path.syntax().text_range();
+ let Some(path) = ModPath::from_src(self.db, path, &mut |range| {
+ self.span_map.span_for_range(range).ctx
+ }) else {
+ return;
+ };
+ let path = Interned::new(path);
+ let ctxt = self.span_map.span_for_range(range).ctx;
let resolver = |path: &_| {
self.def_map
@@ -268,10 +303,10 @@ impl<'a> AssocItemCollector<'a> {
};
match macro_call_as_call_id(
self.db,
- InFile::new(tree_id.file_id(), ast_id),
- path,
+ ast_id,
+ &path,
ctxt,
- expand_to,
+ ExpandTo::Items,
self.module_id.krate(),
resolver,
&mut |ptr, call_id| {
@@ -281,8 +316,7 @@ impl<'a> AssocItemCollector<'a> {
// FIXME: Expansion error?
Ok(call_id) => match call_id.value {
Some(call_id) => {
- self.macro_calls
- .push((InFile::new(tree_id.file_id(), ast_id.upcast()), call_id));
+ self.macro_calls.push((ast_id.upcast(), call_id));
self.collect_macro_items(call_id);
}
None => (),
@@ -291,11 +325,11 @@ impl<'a> AssocItemCollector<'a> {
self.diagnostics.push(DefDiagnostic::unresolved_macro_call(
self.module_id.local_id,
MacroCallKind::FnLike {
- ast_id: InFile::new(tree_id.file_id(), ast_id),
- expand_to,
+ ast_id,
+ expand_to: ExpandTo::Items,
eager: None,
},
- Clone::clone(path),
+ (*path).clone(),
));
}
}
@@ -308,13 +342,29 @@ impl<'a> AssocItemCollector<'a> {
tracing::warn!("macro expansion is too deep");
return;
}
- let tree_id = TreeId::new(macro_call_id.into(), None);
- let item_tree = self.db.file_item_tree(macro_call_id.into());
+ let (syntax, span_map) = self.db.parse_macro_expansion(macro_call_id).value;
+ let old_file_id = mem::replace(&mut self.file_id, macro_call_id.into());
+ let old_ast_id_map = mem::replace(&mut self.ast_id_map, self.db.ast_id_map(self.file_id));
+ let old_span_map = mem::replace(&mut self.span_map, SpanMap::ExpansionSpanMap(span_map));
self.depth += 1;
- for item in item_tree.top_level_items().iter().filter_map(ModItem::as_assoc_item) {
- self.collect_item(&item_tree, tree_id, item);
+
+ let items = ast::MacroItems::cast(syntax.syntax_node()).expect("not `MacroItems`");
+ for item in items.items() {
+ let item = match item {
+ ast::Item::Fn(it) => ast::AssocItem::from(it),
+ ast::Item::Const(it) => it.into(),
+ ast::Item::TypeAlias(it) => it.into(),
+ ast::Item::MacroCall(it) => it.into(),
+ // FIXME: Should error on disallowed item kinds.
+ _ => continue,
+ };
+ self.collect_item(item);
}
+
self.depth -= 1;
+ self.file_id = old_file_id;
+ self.ast_id_map = old_ast_id_map;
+ self.span_map = old_span_map;
}
}
diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs
index 350c97c398..34a129a88e 100644
--- a/crates/hir-def/src/nameres/collector.rs
+++ b/crates/hir-def/src/nameres/collector.rs
@@ -9,8 +9,8 @@ use base_db::{BuiltDependency, Crate, CrateOrigin, LangCrateOrigin};
use cfg::{CfgAtom, CfgExpr, CfgOptions};
use either::Either;
use hir_expand::{
- EditionedFileId, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId,
- MacroDefKind,
+ EditionedFileId, ErasedAstId, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind,
+ MacroDefId, MacroDefKind,
attrs::{Attr, AttrId},
builtin::{find_builtin_attr, find_builtin_derive, find_builtin_macro},
mod_path::{ModPath, PathKind},
@@ -35,9 +35,8 @@ use crate::{
db::DefDatabase,
item_scope::{GlobId, ImportId, ImportOrExternCrate, PerNsGlobImports},
item_tree::{
- self, AttrOwner, FieldsShape, FileItemTreeId, ImportAlias, ImportKind, ItemTree,
- ItemTreeId, ItemTreeNode, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, TreeId,
- UseTreeKind,
+ self, FieldsShape, FileItemTreeId, ImportAlias, ImportKind, ItemTree, ItemTreeId,
+ ItemTreeNode, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, TreeId, UseTreeKind,
},
macro_call_as_call_id,
nameres::{
@@ -141,6 +140,7 @@ struct ImportSource {
id: UseId,
is_prelude: bool,
kind: ImportKind,
+ item_tree_id: ItemTreeId<item_tree::Use>,
}
#[derive(Debug, Eq, PartialEq)]
@@ -166,7 +166,7 @@ impl Import {
path,
alias,
visibility: visibility.clone(),
- source: ImportSource { use_tree: idx, id, is_prelude, kind },
+ source: ImportSource { use_tree: idx, id, is_prelude, kind, item_tree_id },
});
});
}
@@ -576,13 +576,7 @@ impl DefCollector<'_> {
/// use a dummy expander that always errors. This comes with the drawback of macros potentially
/// going out of sync with what the build system sees (since we resolve using VFS state, but
/// Cargo builds only on-disk files). We could and probably should add diagnostics for that.
- fn export_proc_macro(
- &mut self,
- def: ProcMacroDef,
- id: ItemTreeId<item_tree::Function>,
- ast_id: AstId<ast::Fn>,
- fn_id: FunctionId,
- ) {
+ fn export_proc_macro(&mut self, def: ProcMacroDef, ast_id: AstId<ast::Fn>, fn_id: FunctionId) {
let kind = def.kind.to_basedb_kind();
let (expander, kind) = match self.proc_macros.iter().find(|(n, _, _)| n == &def.name) {
Some(_)
@@ -598,7 +592,7 @@ impl DefCollector<'_> {
let proc_macro_id = ProcMacroLoc {
container: self.def_map.crate_root(),
- id,
+ id: ast_id,
expander,
kind,
edition: self.def_map.data.edition,
@@ -866,6 +860,7 @@ impl DefCollector<'_> {
kind: kind @ (ImportKind::Plain | ImportKind::TypeOnly),
id,
use_tree,
+ item_tree_id,
..
} => {
let name = match &import.alias {
@@ -887,9 +882,33 @@ impl DefCollector<'_> {
let imp = ImportOrExternCrate::Import(ImportId { use_: id, idx: use_tree });
tracing::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def);
+ // `extern crate crate_name` things can be re-exported as `pub use crate_name`.
+ // But they cannot be re-exported as `pub use self::crate_name`, `pub use crate::crate_name`
+ // or `pub use ::crate_name`.
+ //
+ // This has been historically allowed, but may be not allowed in future
+ // https://github.com/rust-lang/rust/issues/127909
+ if let Some(def) = def.types.as_mut() {
+ let is_extern_crate_reimport_without_prefix = || {
+ let Some(ImportOrExternCrate::ExternCrate(_)) = def.import else {
+ return false;
+ };
+ let item_tree = item_tree_id.item_tree(self.db);
+ let use_kind = item_tree[item_tree_id.value].use_tree.kind();
+ let UseTreeKind::Single { path, .. } = use_kind else {
+ return false;
+ };
+ matches!(path.kind, PathKind::Plain | PathKind::SELF)
+ && path.segments().len() < 2
+ };
+ if is_extern_crate_reimport_without_prefix() {
+ def.vis = vis;
+ }
+ }
+
self.update(module_id, &[(name.cloned(), def)], vis, Some(imp));
}
- ImportSource { kind: ImportKind::Glob, id, is_prelude, use_tree } => {
+ ImportSource { kind: ImportKind::Glob, id, is_prelude, use_tree, .. } => {
tracing::debug!("glob import: {:?}", import);
let glob = GlobId { use_: id, idx: use_tree };
match def.take_types() {
@@ -978,7 +997,7 @@ impl DefCollector<'_> {
.enum_variants(e)
.variants
.iter()
- .map(|&(variant, ref name)| {
+ .map(|&(variant, ref name, _)| {
let res = PerNs::both(variant.into(), variant.into(), vis, None);
(Some(name.clone()), res)
})
@@ -1150,33 +1169,8 @@ impl DefCollector<'_> {
vis: Visibility,
def_import_type: Option<ImportOrExternCrate>,
) -> bool {
- // `extern crate crate_name` things can be re-exported as `pub use crate_name`.
- // But they cannot be re-exported as `pub use self::crate_name`, `pub use crate::crate_name`
- // or `pub use ::crate_name`.
- //
- // This has been historically allowed, but may be not allowed in future
- // https://github.com/rust-lang/rust/issues/127909
if let Some(def) = defs.types.as_mut() {
- let is_extern_crate_reimport_without_prefix = || {
- let Some(ImportOrExternCrate::ExternCrate(_)) = def.import else {
- return false;
- };
- let Some(ImportOrExternCrate::Import(id)) = def_import_type else {
- return false;
- };
- let use_id = id.use_.lookup(self.db).id;
- let item_tree = use_id.item_tree(self.db);
- let use_kind = item_tree[use_id.value].use_tree.kind();
- let UseTreeKind::Single { path, .. } = use_kind else {
- return false;
- };
- path.segments().len() < 2
- };
- if is_extern_crate_reimport_without_prefix() {
- def.vis = vis;
- } else {
- def.vis = def.vis.min(vis, &self.def_map).unwrap_or(vis);
- }
+ def.vis = def.vis.min(vis, &self.def_map).unwrap_or(vis);
}
if let Some(def) = defs.values.as_mut() {
def.vis = def.vis.min(vis, &self.def_map).unwrap_or(vis);
@@ -1648,7 +1642,8 @@ impl DefCollector<'_> {
import:
Import {
ref path,
- source: ImportSource { use_tree, id, is_prelude: _, kind: _ },
+ source:
+ ImportSource { use_tree, id, is_prelude: _, kind: _, item_tree_id: _ },
..
},
..
@@ -1730,7 +1725,26 @@ 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(self.tree_id, item.into(), &cfg);
+ let ast_id = match item {
+ ModItem::Use(it) => self.item_tree[it].ast_id.erase(),
+ ModItem::ExternCrate(it) => self.item_tree[it].ast_id.erase(),
+ ModItem::ExternBlock(it) => self.item_tree[it].ast_id.erase(),
+ ModItem::Function(it) => self.item_tree[it].ast_id.erase(),
+ ModItem::Struct(it) => self.item_tree[it].ast_id.erase(),
+ ModItem::Union(it) => self.item_tree[it].ast_id.erase(),
+ ModItem::Enum(it) => self.item_tree[it].ast_id.erase(),
+ ModItem::Const(it) => self.item_tree[it].ast_id.erase(),
+ ModItem::Static(it) => self.item_tree[it].ast_id.erase(),
+ ModItem::Trait(it) => self.item_tree[it].ast_id.erase(),
+ ModItem::TraitAlias(it) => self.item_tree[it].ast_id.erase(),
+ ModItem::Impl(it) => self.item_tree[it].ast_id.erase(),
+ ModItem::TypeAlias(it) => self.item_tree[it].ast_id.erase(),
+ ModItem::Mod(it) => self.item_tree[it].ast_id.erase(),
+ ModItem::MacroCall(it) => self.item_tree[it].ast_id.erase(),
+ ModItem::MacroRules(it) => self.item_tree[it].ast_id.erase(),
+ ModItem::Macro2(it) => self.item_tree[it].ast_id.erase(),
+ };
+ self.emit_unconfigured_diagnostic(InFile::new(self.file_id(), ast_id), &cfg);
return;
}
}
@@ -1751,7 +1765,7 @@ impl ModCollector<'_, '_> {
ModItem::Use(item_tree_id) => {
let id = UseLoc {
container: module,
- id: ItemTreeId::new(self.tree_id, item_tree_id),
+ id: InFile::new(self.file_id(), self.item_tree[item_tree_id].ast_id),
}
.intern(db);
let is_prelude = attrs.by_key(sym::prelude_import).exists();
@@ -1770,16 +1784,16 @@ impl ModCollector<'_, '_> {
)
}
ModItem::ExternCrate(item_tree_id) => {
+ let item_tree::ExternCrate { name, visibility, alias, ast_id } =
+ &self.item_tree[item_tree_id];
+
let id = ExternCrateLoc {
container: module,
- id: ItemTreeId::new(self.tree_id, item_tree_id),
+ id: InFile::new(self.tree_id.file_id(), *ast_id),
}
.intern(db);
def_map.modules[self.module_id].scope.define_extern_crate_decl(id);
- let item_tree::ExternCrate { name, visibility, alias, ast_id } =
- &self.item_tree[item_tree_id];
-
let is_self = *name == sym::self_;
let resolved = if is_self {
cov_mark::hit!(extern_crate_self_as);
@@ -1846,7 +1860,7 @@ impl ModCollector<'_, '_> {
ModItem::ExternBlock(block) => {
let extern_block_id = ExternBlockLoc {
container: module,
- id: ItemTreeId::new(self.tree_id, block),
+ id: InFile::new(self.file_id(), self.item_tree[block].ast_id),
}
.intern(db);
self.def_collector.def_map.modules[self.module_id]
@@ -1861,15 +1875,20 @@ impl ModCollector<'_, '_> {
ModItem::MacroRules(id) => self.collect_macro_rules(id, module),
ModItem::Macro2(id) => self.collect_macro_def(id, module),
ModItem::Impl(imp) => {
- let impl_id =
- ImplLoc { container: module, id: ItemTreeId::new(self.tree_id, imp) }
- .intern(db);
+ let impl_id = ImplLoc {
+ container: module,
+ id: InFile::new(self.file_id(), self.item_tree[imp].ast_id),
+ }
+ .intern(db);
self.def_collector.def_map.modules[self.module_id].scope.define_impl(impl_id)
}
ModItem::Function(id) => {
let it = &self.item_tree[id];
- let fn_id =
- FunctionLoc { container, id: ItemTreeId::new(self.tree_id, id) }.intern(db);
+ let fn_id = FunctionLoc {
+ container,
+ id: InFile::new(self.tree_id.file_id(), it.ast_id),
+ }
+ .intern(db);
let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
@@ -1880,7 +1899,6 @@ impl ModCollector<'_, '_> {
if let Some(proc_macro) = attrs.parse_proc_macro_decl(&it.name) {
self.def_collector.export_proc_macro(
proc_macro,
- ItemTreeId::new(self.tree_id, id),
InFile::new(self.file_id(), self.item_tree[id].ast_id()),
fn_id,
);
@@ -1895,7 +1913,7 @@ impl ModCollector<'_, '_> {
let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
update_def(
self.def_collector,
- StructLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
+ StructLoc { container: module, id: InFile::new(self.file_id(), it.ast_id) }
.intern(db)
.into(),
&it.name,
@@ -1909,7 +1927,7 @@ impl ModCollector<'_, '_> {
let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
update_def(
self.def_collector,
- UnionLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
+ UnionLoc { container: module, id: InFile::new(self.file_id(), it.ast_id) }
.intern(db)
.into(),
&it.name,
@@ -1919,9 +1937,11 @@ 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 enum_ = EnumLoc {
+ container: module,
+ id: InFile::new(self.tree_id.file_id(), it.ast_id),
+ }
+ .intern(db);
let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
update_def(self.def_collector, enum_.into(), &it.name, vis, false);
@@ -1929,7 +1949,8 @@ impl ModCollector<'_, '_> {
ModItem::Const(id) => {
let it = &self.item_tree[id];
let const_id =
- ConstLoc { container, id: ItemTreeId::new(self.tree_id, id) }.intern(db);
+ ConstLoc { container, id: InFile::new(self.tree_id.file_id(), it.ast_id) }
+ .intern(db);
match &it.name {
Some(name) => {
@@ -1951,7 +1972,7 @@ impl ModCollector<'_, '_> {
let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
update_def(
self.def_collector,
- StaticLoc { container, id: ItemTreeId::new(self.tree_id, id) }
+ StaticLoc { container, id: InFile::new(self.file_id(), it.ast_id) }
.intern(db)
.into(),
&it.name,
@@ -1965,7 +1986,7 @@ impl ModCollector<'_, '_> {
let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
update_def(
self.def_collector,
- TraitLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
+ TraitLoc { container: module, id: InFile::new(self.file_id(), it.ast_id) }
.intern(db)
.into(),
&it.name,
@@ -1979,9 +2000,12 @@ impl ModCollector<'_, '_> {
let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
update_def(
self.def_collector,
- TraitAliasLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
- .intern(db)
- .into(),
+ TraitAliasLoc {
+ container: module,
+ id: InFile::new(self.file_id(), it.ast_id),
+ }
+ .intern(db)
+ .into(),
&it.name,
vis,
false,
@@ -1993,7 +2017,7 @@ impl ModCollector<'_, '_> {
let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
update_def(
self.def_collector,
- TypeAliasLoc { container, id: ItemTreeId::new(self.tree_id, id) }
+ TypeAliasLoc { container, id: InFile::new(self.file_id(), it.ast_id) }
.intern(db)
.into(),
&it.name,
@@ -2110,8 +2134,10 @@ impl ModCollector<'_, '_> {
match is_enabled {
Err(cfg) => {
self.emit_unconfigured_diagnostic(
- self.tree_id,
- AttrOwner::ModItem(module_id.into()),
+ InFile::new(
+ self.file_id(),
+ self.item_tree[module_id].ast_id.erase(),
+ ),
&cfg,
);
}
@@ -2352,7 +2378,7 @@ impl ModCollector<'_, '_> {
let macro_id = MacroRulesLoc {
container: module,
- id: ItemTreeId::new(self.tree_id, id),
+ id: InFile::new(self.file_id(), mac.ast_id),
flags,
expander,
edition: self.def_collector.def_map.data.edition,
@@ -2420,7 +2446,7 @@ impl ModCollector<'_, '_> {
let macro_id = Macro2Loc {
container: module,
- id: ItemTreeId::new(self.tree_id, id),
+ id: InFile::new(self.file_id(), mac.ast_id),
expander,
allow_internal_unsafe,
edition: self.def_collector.def_map.data.edition,
@@ -2565,16 +2591,16 @@ impl ModCollector<'_, '_> {
self.def_collector.cfg_options.check(cfg) != Some(false)
}
- fn emit_unconfigured_diagnostic(&mut self, tree_id: TreeId, item: AttrOwner, cfg: &CfgExpr) {
+ fn emit_unconfigured_diagnostic(&mut self, ast_id: ErasedAstId, cfg: &CfgExpr) {
self.def_collector.def_map.diagnostics.push(DefDiagnostic::unconfigured_code(
self.module_id,
- tree_id,
- item,
+ ast_id,
cfg.clone(),
self.def_collector.cfg_options.clone(),
));
}
+ #[inline]
fn file_id(&self) -> HirFileId {
self.tree_id.file_id()
}
diff --git a/crates/hir-def/src/nameres/diagnostics.rs b/crates/hir-def/src/nameres/diagnostics.rs
index de3d2f4836..c495a07449 100644
--- a/crates/hir-def/src/nameres/diagnostics.rs
+++ b/crates/hir-def/src/nameres/diagnostics.rs
@@ -3,22 +3,18 @@
use std::ops::Not;
use cfg::{CfgExpr, CfgOptions};
-use hir_expand::{ExpandErrorKind, MacroCallKind, attrs::AttrId, mod_path::ModPath};
+use hir_expand::{ErasedAstId, ExpandErrorKind, MacroCallKind, attrs::AttrId, mod_path::ModPath};
use la_arena::Idx;
use syntax::ast;
-use crate::{
- AstId,
- item_tree::{self, AttrOwner, ItemTreeId, TreeId},
- nameres::LocalModuleId,
-};
+use crate::{AstId, nameres::LocalModuleId};
#[derive(Debug, PartialEq, Eq)]
pub enum DefDiagnosticKind {
UnresolvedModule { ast: AstId<ast::Module>, candidates: Box<[String]> },
UnresolvedExternCrate { ast: AstId<ast::ExternCrate> },
- UnresolvedImport { id: ItemTreeId<item_tree::Use>, index: Idx<ast::UseTree> },
- UnconfiguredCode { tree: TreeId, item: AttrOwner, cfg: CfgExpr, opts: CfgOptions },
+ UnresolvedImport { id: AstId<ast::Use>, index: Idx<ast::UseTree> },
+ UnconfiguredCode { ast_id: ErasedAstId, cfg: CfgExpr, opts: CfgOptions },
UnresolvedMacroCall { ast: MacroCallKind, path: ModPath },
UnimplementedBuiltinMacro { ast: AstId<ast::Macro> },
InvalidDeriveTarget { ast: AstId<ast::Item>, id: usize },
@@ -28,7 +24,7 @@ pub enum DefDiagnosticKind {
}
#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct DefDiagnostics(Option<triomphe::Arc<Box<[DefDiagnostic]>>>);
+pub struct DefDiagnostics(Option<triomphe::ThinArc<(), DefDiagnostic>>);
impl DefDiagnostics {
pub fn new(diagnostics: Vec<DefDiagnostic>) -> Self {
@@ -36,12 +32,12 @@ impl DefDiagnostics {
diagnostics
.is_empty()
.not()
- .then(|| triomphe::Arc::new(diagnostics.into_boxed_slice())),
+ .then(|| triomphe::ThinArc::from_header_and_iter((), diagnostics.into_iter())),
)
}
pub fn iter(&self) -> impl Iterator<Item = &DefDiagnostic> {
- self.0.as_ref().into_iter().flat_map(|it| &***it)
+ self.0.as_ref().into_iter().flat_map(|it| &it.slice)
}
}
@@ -75,7 +71,7 @@ impl DefDiagnostic {
pub(super) fn unresolved_import(
container: LocalModuleId,
- id: ItemTreeId<item_tree::Use>,
+ id: AstId<ast::Use>,
index: Idx<ast::UseTree>,
) -> Self {
Self { in_module: container, kind: DefDiagnosticKind::UnresolvedImport { id, index } }
@@ -92,14 +88,13 @@ impl DefDiagnostic {
pub fn unconfigured_code(
container: LocalModuleId,
- tree: TreeId,
- item: AttrOwner,
+ ast_id: ErasedAstId,
cfg: CfgExpr,
opts: CfgOptions,
) -> Self {
Self {
in_module: container,
- kind: DefDiagnosticKind::UnconfiguredCode { tree, item, cfg, opts },
+ kind: DefDiagnosticKind::UnconfiguredCode { ast_id, cfg, opts },
}
}
diff --git a/crates/hir-def/src/nameres/path_resolution.rs b/crates/hir-def/src/nameres/path_resolution.rs
index 74ce33a641..e0e32a7773 100644
--- a/crates/hir-def/src/nameres/path_resolution.rs
+++ b/crates/hir-def/src/nameres/path_resolution.rs
@@ -12,7 +12,6 @@
use either::Either;
use hir_expand::{
- Lookup,
mod_path::{ModPath, PathKind},
name::Name,
};
@@ -529,23 +528,22 @@ impl DefMap {
// enum variant
cov_mark::hit!(can_import_enum_variant);
- let res =
- db.enum_variants(e).variants.iter().find(|(_, name)| name == segment).map(
- |&(variant, _)| {
- let item_tree_id = variant.lookup(db).id;
- match item_tree_id.item_tree(db)[item_tree_id.value].shape {
- FieldsShape::Record => {
- PerNs::types(variant.into(), Visibility::Public, None)
- }
- FieldsShape::Tuple | FieldsShape::Unit => PerNs::both(
- variant.into(),
- variant.into(),
- Visibility::Public,
- None,
- ),
- }
- },
- );
+ let res = db
+ .enum_variants(e)
+ .variants
+ .iter()
+ .find(|(_, name, _)| name == segment)
+ .map(|&(variant, _, shape)| match shape {
+ FieldsShape::Record => {
+ PerNs::types(variant.into(), Visibility::Public, None)
+ }
+ FieldsShape::Tuple | FieldsShape::Unit => PerNs::both(
+ variant.into(),
+ variant.into(),
+ Visibility::Public,
+ None,
+ ),
+ });
// FIXME: Need to filter visibility here and below? Not sure.
return match res {
Some(res) => {
diff --git a/crates/hir-def/src/resolver.rs b/crates/hir-def/src/resolver.rs
index 16988ddf04..491b6204bc 100644
--- a/crates/hir-def/src/resolver.rs
+++ b/crates/hir-def/src/resolver.rs
@@ -5,21 +5,22 @@ use base_db::Crate;
use hir_expand::{
MacroDefId,
mod_path::{ModPath, PathKind},
- name::Name,
+ name::{AsName, Name},
};
use intern::{Symbol, sym};
use itertools::Itertools as _;
use rustc_hash::FxHashSet;
use smallvec::{SmallVec, smallvec};
use span::SyntaxContext;
+use syntax::ast::HasName;
use triomphe::Arc;
use crate::{
- AdtId, ConstId, ConstParamId, CrateRootModuleId, DefWithBodyId, EnumId, EnumVariantId,
- ExternBlockId, ExternCrateId, FunctionId, FxIndexMap, GenericDefId, GenericParamId, HasModule,
- ImplId, ItemContainerId, ItemTreeLoc, LifetimeParamId, LocalModuleId, Lookup, Macro2Id,
- MacroId, MacroRulesId, ModuleDefId, ModuleId, ProcMacroId, StaticId, StructId, TraitAliasId,
- TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UseId, VariantId,
+ AdtId, AstIdLoc, ConstId, ConstParamId, CrateRootModuleId, DefWithBodyId, EnumId,
+ EnumVariantId, ExternBlockId, ExternCrateId, FunctionId, FxIndexMap, GenericDefId,
+ GenericParamId, HasModule, ImplId, ItemContainerId, LifetimeParamId, LocalModuleId, Lookup,
+ Macro2Id, MacroId, MacroRulesId, ModuleDefId, ModuleId, ProcMacroId, StaticId, StructId,
+ TraitAliasId, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UseId, VariantId,
builtin_type::BuiltinType,
db::DefDatabase,
expr_store::{
@@ -32,10 +33,10 @@ use crate::{
generics::{GenericParams, TypeOrConstParamData},
},
item_scope::{BUILTIN_SCOPE, BuiltinShadowMode, ImportOrExternCrate, ImportOrGlob, ItemScope},
- item_tree::ImportAlias,
lang_item::LangItemTarget,
nameres::{DefMap, LocalDefMap, MacroSubNs, ResolvePathResultPrefixInfo, block_def_map},
per_ns::PerNs,
+ src::HasSource,
type_ref::LifetimeRef,
visibility::{RawVisibility, Visibility},
};
@@ -627,14 +628,14 @@ impl<'db> Resolver<'db> {
.extern_crate_decls()
.filter_map(|id| {
let loc = id.lookup(db);
- let tree = loc.item_tree_id().item_tree(db);
- match &tree[loc.id.value].alias {
- Some(alias) => match alias {
- ImportAlias::Underscore => None,
- ImportAlias::Alias(name) => Some(name.clone()),
- },
- None => Some(tree[loc.id.value].name.clone()),
- }
+ let extern_crate = loc.source(db);
+ // If there is a rename (`as x`), extract the renamed name, or remove the `extern crate`
+ // if it is an underscore.
+ extern_crate
+ .value
+ .rename()
+ .map(|a| a.name().map(|it| it.as_name()))
+ .unwrap_or_else(|| extern_crate.value.name_ref().map(|it| it.as_name()))
})
}
@@ -1471,10 +1472,7 @@ impl HasResolver for MacroRulesId {
fn lookup_resolver(
db: &dyn DefDatabase,
- lookup: impl Lookup<
- Database = dyn DefDatabase,
- Data = impl ItemTreeLoc<Container = impl HasResolver>,
- >,
+ lookup: impl Lookup<Database = dyn DefDatabase, Data = impl AstIdLoc<Container = impl HasResolver>>,
) -> Resolver<'_> {
lookup.lookup(db).container().resolver(db)
}
diff --git a/crates/hir-def/src/signatures.rs b/crates/hir-def/src/signatures.rs
index 44cfd72c48..b7d29f54d0 100644
--- a/crates/hir-def/src/signatures.rs
+++ b/crates/hir-def/src/signatures.rs
@@ -4,21 +4,25 @@ use std::ops::Not as _;
use bitflags::bitflags;
use cfg::{CfgExpr, CfgOptions};
-use either::Either;
-use hir_expand::{InFile, Intern, Lookup, name::Name};
+use hir_expand::{
+ InFile, Intern, Lookup,
+ name::{AsName, Name},
+};
use intern::{Symbol, sym};
use la_arena::{Arena, Idx};
use rustc_abi::{IntegerType, ReprOptions};
use syntax::{
- AstNode, SyntaxNodePtr,
- ast::{self, HasGenericParams, IsString},
+ NodeOrToken, SyntaxNodePtr, T,
+ ast::{self, HasGenericParams, HasName, HasVisibility, IsString},
};
use thin_vec::ThinVec;
use triomphe::Arc;
use crate::{
- ConstId, EnumId, EnumVariantId, EnumVariantLoc, FunctionId, HasModule, ImplId, ItemContainerId,
- ModuleId, StaticId, StructId, TraitAliasId, TraitId, TypeAliasId, UnionId, VariantId,
+ ConstId, EnumId, EnumVariantId, EnumVariantLoc, ExternBlockId, FunctionId, HasModule, ImplId,
+ ItemContainerId, ModuleId, StaticId, StructId, TraitAliasId, TraitId, TypeAliasId, UnionId,
+ VariantId,
+ attr::Attrs,
db::DefDatabase,
expr_store::{
ExpressionStore, ExpressionStoreSourceMap,
@@ -28,15 +32,17 @@ use crate::{
},
},
hir::{ExprId, PatId, generics::GenericParams},
- item_tree::{
- AttrOwner, Field, FieldParent, FieldsShape, FileItemTreeId, ItemTree, ItemTreeId, ModItem,
- RawVisibility, RawVisibilityId,
- },
+ item_tree::{FieldsShape, RawVisibility, visibility_from_ast},
lang_item::LangItem,
src::HasSource,
type_ref::{TraitRef, TypeBound, TypeRefId},
};
+#[inline]
+fn as_name_opt(name: Option<ast::Name>) -> Name {
+ name.map_or_else(Name::missing, |it| it.as_name())
+}
+
#[derive(Debug, PartialEq, Eq)]
pub struct StructSignature {
pub name: Name,
@@ -70,8 +76,8 @@ bitflags! {
impl StructSignature {
pub fn query(db: &dyn DefDatabase, id: StructId) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) {
let loc = id.lookup(db);
- let item_tree = loc.id.item_tree(db);
- let attrs = item_tree.attrs(db, loc.container.krate, ModItem::from(loc.id.value).into());
+ let InFile { file_id, value: source } = loc.source(db);
+ let attrs = db.attrs(id.into());
let mut flags = StructFlags::empty();
if attrs.by_key(sym::rustc_has_incoherent_inherent_impls).exists() {
@@ -91,23 +97,23 @@ impl StructSignature {
}
}
let repr = attrs.repr();
+ let shape = adt_shape(source.kind());
- let hir_expand::files::InFileWrapper { file_id, value } = loc.source(db);
let (store, generic_params, source_map) = lower_generic_params(
db,
loc.container,
id.into(),
file_id,
- value.generic_param_list(),
- value.where_clause(),
+ source.generic_param_list(),
+ source.where_clause(),
);
(
Arc::new(StructSignature {
generic_params,
store,
flags,
- shape: item_tree[loc.id.value].shape,
- name: item_tree[loc.id.value].name.clone(),
+ shape,
+ name: as_name_opt(source.name()),
repr,
}),
Arc::new(source_map),
@@ -115,6 +121,15 @@ impl StructSignature {
}
}
+#[inline]
+fn adt_shape(adt_kind: ast::StructKind) -> FieldsShape {
+ match adt_kind {
+ ast::StructKind::Record(_) => FieldsShape::Record,
+ ast::StructKind::Tuple(_) => FieldsShape::Tuple,
+ ast::StructKind::Unit => FieldsShape::Unit,
+ }
+}
+
#[derive(Debug, PartialEq, Eq)]
pub struct UnionSignature {
pub name: Name,
@@ -127,9 +142,7 @@ pub struct UnionSignature {
impl UnionSignature {
pub fn query(db: &dyn DefDatabase, id: UnionId) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) {
let loc = id.lookup(db);
- let krate = loc.container.krate;
- let item_tree = loc.id.item_tree(db);
- let attrs = item_tree.attrs(db, krate, ModItem::from(loc.id.value).into());
+ let attrs = db.attrs(id.into());
let mut flags = StructFlags::empty();
if attrs.by_key(sym::rustc_has_incoherent_inherent_impls).exists() {
flags |= StructFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPLS;
@@ -140,14 +153,14 @@ impl UnionSignature {
let repr = attrs.repr();
- let hir_expand::files::InFileWrapper { file_id, value } = loc.source(db);
+ let InFile { file_id, value: source } = loc.source(db);
let (store, generic_params, source_map) = lower_generic_params(
db,
loc.container,
id.into(),
file_id,
- value.generic_param_list(),
- value.where_clause(),
+ source.generic_param_list(),
+ source.where_clause(),
);
(
Arc::new(UnionSignature {
@@ -155,7 +168,7 @@ impl UnionSignature {
store,
flags,
repr,
- name: item_tree[loc.id.value].name.clone(),
+ name: as_name_opt(source.name()),
}),
Arc::new(source_map),
)
@@ -181,8 +194,7 @@ pub struct EnumSignature {
impl EnumSignature {
pub fn query(db: &dyn DefDatabase, id: EnumId) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) {
let loc = id.lookup(db);
- let item_tree = loc.id.item_tree(db);
- let attrs = item_tree.attrs(db, loc.container.krate, ModItem::from(loc.id.value).into());
+ let attrs = db.attrs(id.into());
let mut flags = EnumFlags::empty();
if attrs.by_key(sym::rustc_has_incoherent_inherent_impls).exists() {
flags |= EnumFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPLS;
@@ -190,14 +202,14 @@ impl EnumSignature {
let repr = attrs.repr();
- let hir_expand::files::InFileWrapper { file_id, value } = loc.source(db);
+ let InFile { file_id, value: source } = loc.source(db);
let (store, generic_params, source_map) = lower_generic_params(
db,
loc.container,
id.into(),
file_id,
- value.generic_param_list(),
- value.where_clause(),
+ source.generic_param_list(),
+ source.where_clause(),
);
(
@@ -206,7 +218,7 @@ impl EnumSignature {
store,
flags,
repr,
- name: item_tree[loc.id.value].name.clone(),
+ name: as_name_opt(source.name()),
}),
Arc::new(source_map),
)
@@ -239,10 +251,9 @@ pub struct ConstSignature {
impl ConstSignature {
pub fn query(db: &dyn DefDatabase, id: ConstId) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) {
let loc = id.lookup(db);
- let item_tree = loc.id.item_tree(db);
let module = loc.container.module(db);
- let attrs = item_tree.attrs(db, module.krate, ModItem::from(loc.id.value).into());
+ let attrs = db.attrs(id.into());
let mut flags = ConstFlags::empty();
if attrs.by_key(sym::rustc_allow_incoherent_impl).exists() {
flags |= ConstFlags::RUSTC_ALLOW_INCOHERENT_IMPL;
@@ -253,14 +264,14 @@ impl ConstSignature {
}
let (store, source_map, type_ref) =
- crate::expr_store::lower::lower_type_ref(db, module, source.map(|it| it.ty()));
+ crate::expr_store::lower::lower_type_ref(db, module, source.as_ref().map(|it| it.ty()));
(
Arc::new(ConstSignature {
store: Arc::new(store),
type_ref,
flags,
- name: item_tree[loc.id.value].name.clone(),
+ name: source.value.name().map(|it| it.as_name()),
}),
Arc::new(source_map),
)
@@ -295,10 +306,9 @@ pub struct StaticSignature {
impl StaticSignature {
pub fn query(db: &dyn DefDatabase, id: StaticId) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) {
let loc = id.lookup(db);
- let item_tree = loc.id.item_tree(db);
let module = loc.container.module(db);
- let attrs = item_tree.attrs(db, module.krate, ModItem::from(loc.id.value).into());
+ let attrs = db.attrs(id.into());
let mut flags = StaticFlags::empty();
if attrs.by_key(sym::rustc_allow_incoherent_impl).exists() {
flags |= StaticFlags::RUSTC_ALLOW_INCOHERENT_IMPL;
@@ -323,14 +333,14 @@ impl StaticSignature {
}
let (store, source_map, type_ref) =
- crate::expr_store::lower::lower_type_ref(db, module, source.map(|it| it.ty()));
+ crate::expr_store::lower::lower_type_ref(db, module, source.as_ref().map(|it| it.ty()));
(
Arc::new(StaticSignature {
store: Arc::new(store),
type_ref,
flags,
- name: item_tree[loc.id.value].name.clone(),
+ name: as_name_opt(source.value.name()),
}),
Arc::new(source_map),
)
@@ -407,10 +417,9 @@ pub struct TraitSignature {
impl TraitSignature {
pub fn query(db: &dyn DefDatabase, id: TraitId) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) {
let loc = id.lookup(db);
- let item_tree = loc.id.item_tree(db);
let mut flags = TraitFlags::empty();
- let attrs = item_tree.attrs(db, loc.container.krate, ModItem::from(loc.id.value).into());
+ let attrs = db.attrs(id.into());
let source = loc.source(db);
if source.value.auto_token().is_some() {
flags.insert(TraitFlags::AUTO);
@@ -446,15 +455,11 @@ impl TraitSignature {
flags |= TraitFlags::SKIP_BOXED_SLICE_DURING_METHOD_DISPATCH;
}
+ let name = as_name_opt(source.value.name());
let (store, source_map, generic_params) = lower_trait(db, loc.container, source, id);
(
- Arc::new(TraitSignature {
- store: Arc::new(store),
- generic_params,
- flags,
- name: item_tree[loc.id.value].name.clone(),
- }),
+ Arc::new(TraitSignature { store: Arc::new(store), generic_params, flags, name }),
Arc::new(source_map),
)
}
@@ -473,17 +478,13 @@ impl TraitAliasSignature {
id: TraitAliasId,
) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) {
let loc = id.lookup(db);
- let item_tree = loc.id.item_tree(db);
let source = loc.source(db);
+ let name = as_name_opt(source.value.name());
let (store, source_map, generic_params) = lower_trait_alias(db, loc.container, source, id);
(
- Arc::new(TraitAliasSignature {
- generic_params,
- store: Arc::new(store),
- name: item_tree[loc.id.value].name.clone(),
- }),
+ Arc::new(TraitAliasSignature { generic_params, store: Arc::new(store), name }),
Arc::new(source_map),
)
}
@@ -530,10 +531,9 @@ impl FunctionSignature {
) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) {
let loc = id.lookup(db);
let module = loc.container.module(db);
- let item_tree = loc.id.item_tree(db);
let mut flags = FnFlags::empty();
- let attrs = item_tree.attrs(db, module.krate, ModItem::from(loc.id.value).into());
+ let attrs = db.attrs(id.into());
if attrs.by_key(sym::rustc_allow_incoherent_impl).exists() {
flags.insert(FnFlags::RUSTC_ALLOW_INCOHERENT_IMPL);
}
@@ -568,6 +568,7 @@ impl FunctionSignature {
flags.insert(FnFlags::HAS_BODY);
}
+ let name = as_name_opt(source.value.name());
let abi = source.value.abi().map(|abi| {
abi.abi_string().map_or_else(|| sym::C, |it| Symbol::intern(it.text_without_quotes()))
});
@@ -588,7 +589,7 @@ impl FunctionSignature {
abi,
flags,
legacy_const_generics_indices,
- name: item_tree[loc.id.value].name.clone(),
+ name,
}),
Arc::new(source_map),
)
@@ -662,14 +663,9 @@ impl TypeAliasSignature {
id: TypeAliasId,
) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) {
let loc = id.lookup(db);
- let item_tree = loc.id.item_tree(db);
let mut flags = TypeAliasFlags::empty();
- let attrs = item_tree.attrs(
- db,
- loc.container.module(db).krate(),
- ModItem::from(loc.id.value).into(),
- );
+ let attrs = db.attrs(id.into());
if attrs.by_key(sym::rustc_has_incoherent_inherent_impls).exists() {
flags.insert(TypeAliasFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPL);
}
@@ -680,6 +676,7 @@ impl TypeAliasSignature {
flags.insert(TypeAliasFlags::IS_EXTERN);
}
let source = loc.source(db);
+ let name = as_name_opt(source.value.name());
let (store, source_map, generic_params, bounds, ty) =
lower_type_alias(db, loc.container.module(db), source, id);
@@ -689,7 +686,7 @@ impl TypeAliasSignature {
generic_params,
flags,
bounds,
- name: item_tree[loc.id.value].name.clone(),
+ name,
ty,
}),
Arc::new(source_map),
@@ -743,104 +740,41 @@ impl VariantFields {
let (shape, (fields, store, source_map)) = match id {
VariantId::EnumVariantId(id) => {
let loc = id.lookup(db);
- let item_tree = loc.id.item_tree(db);
let parent = loc.parent.lookup(db);
- let variant = &item_tree[loc.id.value];
- (
- variant.shape,
- lower_fields(
- db,
- parent.container,
- &item_tree,
- FieldParent::EnumVariant(loc.id.value),
- loc.source(db).map(|src| {
- variant.fields.iter().zip(
- src.field_list()
- .map(|it| {
- match it {
- ast::FieldList::RecordFieldList(record_field_list) => {
- Either::Left(record_field_list.fields().map(|it| {
- (SyntaxNodePtr::new(it.syntax()), it.ty())
- }))
- }
- ast::FieldList::TupleFieldList(field_list) => {
- Either::Right(field_list.fields().map(|it| {
- (SyntaxNodePtr::new(it.syntax()), it.ty())
- }))
- }
- }
- .into_iter()
- })
- .into_iter()
- .flatten(),
- )
- }),
- Some(item_tree[parent.id.value].visibility),
- ),
- )
+ let source = loc.source(db);
+ let shape = adt_shape(source.value.kind());
+ let span_map = db.span_map(source.file_id);
+ let override_visibility = visibility_from_ast(
+ db,
+ source.value.parent_enum().visibility(),
+ &mut |range| span_map.span_for_range(range).ctx,
+ );
+ let fields = lower_field_list(
+ db,
+ parent.container,
+ source.map(|src| src.field_list()),
+ Some(override_visibility),
+ );
+ (shape, fields)
}
VariantId::StructId(id) => {
let loc = id.lookup(db);
- let item_tree = loc.id.item_tree(db);
- let strukt = &item_tree[loc.id.value];
- (
- strukt.shape,
- lower_fields(
- db,
- loc.container,
- &item_tree,
- FieldParent::Struct(loc.id.value),
- loc.source(db).map(|src| {
- strukt.fields.iter().zip(
- src.field_list()
- .map(|it| {
- match it {
- ast::FieldList::RecordFieldList(record_field_list) => {
- Either::Left(record_field_list.fields().map(|it| {
- (SyntaxNodePtr::new(it.syntax()), it.ty())
- }))
- }
- ast::FieldList::TupleFieldList(field_list) => {
- Either::Right(field_list.fields().map(|it| {
- (SyntaxNodePtr::new(it.syntax()), it.ty())
- }))
- }
- }
- .into_iter()
- })
- .into_iter()
- .flatten(),
- )
- }),
- None,
- ),
- )
+ let source = loc.source(db);
+ let shape = adt_shape(source.value.kind());
+ let fields =
+ lower_field_list(db, loc.container, source.map(|src| src.field_list()), None);
+ (shape, fields)
}
VariantId::UnionId(id) => {
let loc = id.lookup(db);
- let item_tree = loc.id.item_tree(db);
- let union = &item_tree[loc.id.value];
- (
- FieldsShape::Record,
- lower_fields(
- db,
- loc.container,
- &item_tree,
- FieldParent::Union(loc.id.value),
- loc.source(db).map(|src| {
- union.fields.iter().zip(
- src.record_field_list()
- .map(|it| {
- it.fields()
- .map(|it| (SyntaxNodePtr::new(it.syntax()), it.ty()))
- })
- .into_iter()
- .flatten(),
- )
- }),
- None,
- ),
- )
+ let source = loc.source(db);
+ let fields = lower_field_list(
+ db,
+ loc.container,
+ source.map(|src| src.record_field_list().map(ast::FieldList::RecordFieldList)),
+ None,
+ );
+ (FieldsShape::Record, fields)
}
};
@@ -860,39 +794,81 @@ impl VariantFields {
}
}
-fn lower_fields<'a>(
+fn lower_field_list(
db: &dyn DefDatabase,
module: ModuleId,
- item_tree: &ItemTree,
- parent: FieldParent,
- fields: InFile<impl Iterator<Item = (&'a Field, (SyntaxNodePtr, Option<ast::Type>))>>,
- override_visibility: Option<RawVisibilityId>,
+ fields: InFile<Option<ast::FieldList>>,
+ override_visibility: Option<RawVisibility>,
+) -> (Arena<FieldData>, ExpressionStore, ExpressionStoreSourceMap) {
+ let file_id = fields.file_id;
+ match fields.value {
+ Some(ast::FieldList::RecordFieldList(fields)) => lower_fields(
+ db,
+ module,
+ InFile::new(file_id, fields.fields().map(|field| (field.ty(), field))),
+ |_, field| as_name_opt(field.name()),
+ override_visibility,
+ ),
+ Some(ast::FieldList::TupleFieldList(fields)) => lower_fields(
+ db,
+ module,
+ InFile::new(file_id, fields.fields().map(|field| (field.ty(), field))),
+ |idx, _| Name::new_tuple_field(idx),
+ override_visibility,
+ ),
+ None => lower_fields(
+ db,
+ module,
+ InFile::new(file_id, std::iter::empty::<(Option<ast::Type>, ast::RecordField)>()),
+ |_, _| Name::missing(),
+ None,
+ ),
+ }
+}
+
+fn lower_fields<Field: ast::HasAttrs + ast::HasVisibility>(
+ db: &dyn DefDatabase,
+ module: ModuleId,
+ fields: InFile<impl Iterator<Item = (Option<ast::Type>, Field)>>,
+ mut field_name: impl FnMut(usize, &Field) -> Name,
+ override_visibility: Option<RawVisibility>,
) -> (Arena<FieldData>, ExpressionStore, ExpressionStoreSourceMap) {
let mut arena = Arena::new();
let cfg_options = module.krate.cfg_options(db);
let mut col = ExprCollector::new(db, module, fields.file_id);
- for (idx, (field, (ptr, ty))) in fields.value.enumerate() {
- let attr_owner = AttrOwner::make_field_indexed(parent, idx);
- let attrs = item_tree.attrs(db, module.krate, attr_owner);
- if attrs.is_cfg_enabled(cfg_options) {
- arena.alloc(FieldData {
- name: field.name.clone(),
- type_ref: col
- .lower_type_ref_opt(ty, &mut ExprCollector::impl_trait_error_allocator),
- visibility: item_tree[override_visibility.unwrap_or(field.visibility)].clone(),
- is_unsafe: field.is_unsafe,
- });
- } else {
- col.source_map.diagnostics.push(
- crate::expr_store::ExpressionStoreDiagnostics::InactiveCode {
- node: InFile::new(fields.file_id, ptr),
- cfg: attrs.cfg().unwrap(),
- opts: cfg_options.clone(),
- },
- );
+ let mut idx = 0;
+ for (ty, field) in fields.value {
+ match Attrs::is_cfg_enabled_for(db, &field, col.span_map(), cfg_options) {
+ Ok(()) => {
+ let type_ref =
+ col.lower_type_ref_opt(ty, &mut ExprCollector::impl_trait_error_allocator);
+ let visibility = override_visibility.clone().unwrap_or_else(|| {
+ visibility_from_ast(db, field.visibility(), &mut |range| {
+ col.span_map().span_for_range(range).ctx
+ })
+ });
+ let is_unsafe = field
+ .syntax()
+ .children_with_tokens()
+ .filter_map(NodeOrToken::into_token)
+ .any(|token| token.kind() == T![unsafe]);
+ let name = field_name(idx, &field);
+ arena.alloc(FieldData { name, type_ref, visibility, is_unsafe });
+ idx += 1;
+ }
+ Err(cfg) => {
+ col.source_map.diagnostics.push(
+ crate::expr_store::ExpressionStoreDiagnostics::InactiveCode {
+ node: InFile::new(fields.file_id, SyntaxNodePtr::new(field.syntax())),
+ cfg,
+ opts: cfg_options.clone(),
+ },
+ );
+ }
}
}
let store = col.store.finish();
+ arena.shrink_to_fit();
(arena, store, col.source_map)
}
@@ -905,7 +881,7 @@ pub struct InactiveEnumVariantCode {
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct EnumVariants {
- pub variants: Box<[(EnumVariantId, Name)]>,
+ pub variants: Box<[(EnumVariantId, Name, FieldsShape)]>,
}
impl EnumVariants {
@@ -914,30 +890,38 @@ impl EnumVariants {
e: EnumId,
) -> (Arc<EnumVariants>, Option<Arc<ThinVec<InactiveEnumVariantCode>>>) {
let loc = e.lookup(db);
- let item_tree = loc.id.item_tree(db);
+ let source = loc.source(db);
+ let ast_id_map = db.ast_id_map(source.file_id);
+ let span_map = db.span_map(source.file_id);
let mut diagnostics = ThinVec::new();
let cfg_options = loc.container.krate.cfg_options(db);
let mut index = 0;
- let variants = FileItemTreeId::range_iter(item_tree[loc.id.value].variants.clone())
+ let Some(variants) = source.value.variant_list() else {
+ return (Arc::new(EnumVariants { variants: Box::default() }), None);
+ };
+ let variants = variants
+ .variants()
.filter_map(|variant| {
- let attrs = item_tree.attrs(db, loc.container.krate, variant.into());
- if attrs.is_cfg_enabled(cfg_options) {
- let enum_variant = EnumVariantLoc {
- id: ItemTreeId::new(loc.id.tree_id(), variant),
- parent: e,
- index,
+ let ast_id = ast_id_map.ast_id(&variant);
+ match Attrs::is_cfg_enabled_for(db, &variant, span_map.as_ref(), cfg_options) {
+ Ok(()) => {
+ let enum_variant =
+ EnumVariantLoc { id: source.with_value(ast_id), parent: e, index }
+ .intern(db);
+ index += 1;
+ let name = as_name_opt(variant.name());
+ let shape = adt_shape(variant.kind());
+ Some((enum_variant, name, shape))
+ }
+ Err(cfg) => {
+ diagnostics.push(InactiveEnumVariantCode {
+ ast_id,
+ cfg,
+ opts: cfg_options.clone(),
+ });
+ None
}
- .intern(db);
- index += 1;
- Some((enum_variant, item_tree[variant].name.clone()))
- } else {
- diagnostics.push(InactiveEnumVariantCode {
- ast_id: item_tree[variant].ast_id,
- cfg: attrs.cfg().unwrap(),
- opts: cfg_options.clone(),
- });
- None
}
})
.collect();
@@ -949,12 +933,18 @@ impl EnumVariants {
}
pub fn variant(&self, name: &Name) -> Option<EnumVariantId> {
- self.variants.iter().find_map(|(v, n)| if n == name { Some(*v) } else { None })
+ self.variants.iter().find_map(|(v, n, _)| if n == name { Some(*v) } else { None })
+ }
+
+ pub fn variant_name_by_id(&self, variant_id: EnumVariantId) -> Option<Name> {
+ self.variants
+ .iter()
+ .find_map(|(id, name, _)| if *id == variant_id { Some(name.clone()) } else { None })
}
// [Adopted from rustc](https://github.com/rust-lang/rust/blob/bd53aa3bf7a24a70d763182303bd75e5fc51a9af/compiler/rustc_middle/src/ty/adt.rs#L446-L448)
pub fn is_payload_free(&self, db: &dyn DefDatabase) -> bool {
- self.variants.iter().all(|&(v, _)| {
+ self.variants.iter().all(|&(v, _, _)| {
// The condition check order is slightly modified from rustc
// to improve performance by early returning with relatively fast checks
let variant = &db.variant_fields(v.into());
@@ -973,3 +963,17 @@ impl EnumVariants {
})
}
}
+
+pub(crate) fn extern_block_abi_query(
+ db: &dyn DefDatabase,
+ extern_block: ExternBlockId,
+) -> Option<Symbol> {
+ let source = extern_block.lookup(db).source(db);
+ source.value.abi().map(|abi| {
+ match abi.abi_string() {
+ Some(tok) => Symbol::intern(tok.text_without_quotes()),
+ // `extern` default to be `extern "C"`.
+ _ => sym::C,
+ }
+ })
+}
diff --git a/crates/hir-def/src/src.rs b/crates/hir-def/src/src.rs
index 3867f39b8b..aa373a27b0 100644
--- a/crates/hir-def/src/src.rs
+++ b/crates/hir-def/src/src.rs
@@ -1,15 +1,13 @@
//! Utilities for mapping between hir IDs and the surface syntax.
use either::Either;
-use hir_expand::InFile;
-use la_arena::ArenaMap;
+use hir_expand::{AstId, InFile};
+use la_arena::{Arena, ArenaMap, Idx};
use syntax::{AstNode, AstPtr, ast};
use crate::{
- GenericDefId, ItemTreeLoc, LocalFieldId, LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup,
- UseId, VariantId,
- db::DefDatabase,
- item_tree::{AttrOwner, FieldParent, ItemTreeNode},
+ AstIdLoc, GenericDefId, LocalFieldId, LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup,
+ UseId, VariantId, attr::Attrs, db::DefDatabase,
};
pub trait HasSource {
@@ -23,18 +21,13 @@ pub trait HasSource {
impl<T> HasSource for T
where
- T: ItemTreeLoc,
- T::Id: ItemTreeNode,
+ T: AstIdLoc,
{
- type Value = <T::Id as ItemTreeNode>::Source;
+ type Value = T::Ast;
fn ast_ptr(&self, db: &dyn DefDatabase) -> InFile<AstPtr<Self::Value>> {
- let id = self.item_tree_id();
- let file_id = id.file_id();
- let tree = id.item_tree(db);
- let ast_id_map = db.ast_id_map(file_id);
- let node = &tree[id.value];
-
- InFile::new(file_id, ast_id_map.get(node.ast_id()))
+ let id = self.ast_id();
+ let ast_id_map = db.ast_id_map(id.file_id);
+ InFile::new(id.file_id, ast_id_map.get(id.value))
}
}
@@ -43,18 +36,37 @@ pub trait HasChildSource<ChildId> {
fn child_source(&self, db: &dyn DefDatabase) -> InFile<ArenaMap<ChildId, Self::Value>>;
}
+/// Maps a `UseTree` contained in this import back to its AST node.
+pub fn use_tree_to_ast(
+ db: &dyn DefDatabase,
+ use_ast_id: AstId<ast::Use>,
+ index: Idx<ast::UseTree>,
+) -> ast::UseTree {
+ use_tree_source_map(db, use_ast_id)[index].clone()
+}
+
+/// Maps a `UseTree` contained in this import back to its AST node.
+fn use_tree_source_map(db: &dyn DefDatabase, use_ast_id: AstId<ast::Use>) -> Arena<ast::UseTree> {
+ // Re-lower the AST item and get the source map.
+ // Note: The AST unwraps are fine, since if they fail we should have never obtained `index`.
+ let ast = use_ast_id.to_node(db);
+ let ast_use_tree = ast.use_tree().expect("missing `use_tree`");
+ let mut span_map = None;
+ crate::item_tree::lower_use_tree(db, ast_use_tree, &mut |range| {
+ span_map.get_or_insert_with(|| db.span_map(use_ast_id.file_id)).span_for_range(range).ctx
+ })
+ .expect("failed to lower use tree")
+ .1
+}
+
impl HasChildSource<la_arena::Idx<ast::UseTree>> for UseId {
type Value = ast::UseTree;
fn child_source(
&self,
db: &dyn DefDatabase,
) -> InFile<ArenaMap<la_arena::Idx<ast::UseTree>, Self::Value>> {
- let loc = &self.lookup(db);
- let use_ = &loc.id.item_tree(db)[loc.id.value];
- InFile::new(
- loc.id.file_id(),
- use_.use_tree_source_map(db, loc.id.file_id()).into_iter().collect(),
- )
+ let loc = self.lookup(db);
+ InFile::new(loc.id.file_id, use_tree_source_map(db, loc.id).into_iter().collect())
}
}
@@ -124,49 +136,30 @@ impl HasChildSource<LocalFieldId> for VariantId {
type Value = Either<ast::TupleField, ast::RecordField>;
fn child_source(&self, db: &dyn DefDatabase) -> InFile<ArenaMap<LocalFieldId, Self::Value>> {
- let item_tree;
- let (src, parent, container) = match *self {
+ let (src, container) = match *self {
VariantId::EnumVariantId(it) => {
let lookup = it.lookup(db);
- item_tree = lookup.id.item_tree(db);
- (
- lookup.source(db).map(|it| it.kind()),
- FieldParent::EnumVariant(lookup.id.value),
- lookup.parent.lookup(db).container,
- )
+ (lookup.source(db).map(|it| it.kind()), lookup.parent.lookup(db).container)
}
VariantId::StructId(it) => {
let lookup = it.lookup(db);
- item_tree = lookup.id.item_tree(db);
- (
- lookup.source(db).map(|it| it.kind()),
- FieldParent::Struct(lookup.id.value),
- lookup.container,
- )
+ (lookup.source(db).map(|it| it.kind()), lookup.container)
}
VariantId::UnionId(it) => {
let lookup = it.lookup(db);
- item_tree = lookup.id.item_tree(db);
- (
- lookup.source(db).map(|it| it.kind()),
- FieldParent::Union(lookup.id.value),
- lookup.container,
- )
+ (lookup.source(db).map(|it| it.kind()), lookup.container)
}
};
-
+ let span_map = db.span_map(src.file_id);
let mut map = ArenaMap::new();
match &src.value {
ast::StructKind::Tuple(fl) => {
let cfg_options = container.krate.cfg_options(db);
let mut idx = 0;
- for (i, fd) in fl.fields().enumerate() {
- let attrs = item_tree.attrs(
- db,
- container.krate,
- AttrOwner::make_field_indexed(parent, i),
- );
- if !attrs.is_cfg_enabled(cfg_options) {
+ for fd in fl.fields() {
+ let enabled =
+ Attrs::is_cfg_enabled_for(db, &fd, span_map.as_ref(), cfg_options).is_ok();
+ if !enabled {
continue;
}
map.insert(
@@ -179,13 +172,10 @@ impl HasChildSource<LocalFieldId> for VariantId {
ast::StructKind::Record(fl) => {
let cfg_options = container.krate.cfg_options(db);
let mut idx = 0;
- for (i, fd) in fl.fields().enumerate() {
- let attrs = item_tree.attrs(
- db,
- container.krate,
- AttrOwner::make_field_indexed(parent, i),
- );
- if !attrs.is_cfg_enabled(cfg_options) {
+ for fd in fl.fields() {
+ let enabled =
+ Attrs::is_cfg_enabled_for(db, &fd, span_map.as_ref(), cfg_options).is_ok();
+ if !enabled {
continue;
}
map.insert(
@@ -195,7 +185,7 @@ impl HasChildSource<LocalFieldId> for VariantId {
idx += 1;
}
}
- _ => (),
+ ast::StructKind::Unit => (),
}
InFile::new(src.file_id, map)
}
diff --git a/crates/hir-def/src/visibility.rs b/crates/hir-def/src/visibility.rs
index 3c67ee9fe5..14d67ea804 100644
--- a/crates/hir-def/src/visibility.rs
+++ b/crates/hir-def/src/visibility.rs
@@ -2,16 +2,18 @@
use std::iter;
-use hir_expand::Lookup;
+use hir_expand::{InFile, Lookup};
use la_arena::ArenaMap;
+use syntax::ast::{self, HasVisibility};
use triomphe::Arc;
use crate::{
- ConstId, FunctionId, HasModule, ItemContainerId, ItemLoc, ItemTreeLoc, LocalFieldId,
- LocalModuleId, ModuleId, TraitId, TypeAliasId, VariantId,
+ ConstId, FunctionId, HasModule, ItemContainerId, LocalFieldId, LocalModuleId, ModuleId,
+ TraitId, TypeAliasId, VariantId,
db::DefDatabase,
nameres::DefMap,
resolver::{HasResolver, Resolver},
+ src::HasSource,
};
pub use crate::item_tree::{RawVisibility, VisibilityExplicitness};
@@ -217,49 +219,69 @@ pub(crate) fn field_visibilities_query(
for (field_id, field_data) in fields.iter() {
res.insert(field_id, Visibility::resolve(db, &resolver, &field_data.visibility));
}
+ res.shrink_to_fit();
Arc::new(res)
}
+pub fn visibility_from_ast(
+ db: &dyn DefDatabase,
+ resolver: &Resolver<'_>,
+ ast_vis: InFile<Option<ast::Visibility>>,
+) -> Visibility {
+ let mut span_map = None;
+ let raw_vis = crate::item_tree::visibility_from_ast(db, ast_vis.value, &mut |range| {
+ span_map.get_or_insert_with(|| db.span_map(ast_vis.file_id)).span_for_range(range).ctx
+ });
+ Visibility::resolve(db, resolver, &raw_vis)
+}
+
+fn trait_item_visibility(
+ db: &dyn DefDatabase,
+ resolver: &Resolver<'_>,
+ container: ItemContainerId,
+) -> Option<Visibility> {
+ match container {
+ ItemContainerId::TraitId(trait_) => Some(trait_visibility(db, resolver, trait_)),
+ _ => None,
+ }
+}
+
/// Resolve visibility of a function.
pub(crate) fn function_visibility_query(db: &dyn DefDatabase, def: FunctionId) -> Visibility {
- let resolver = def.resolver(db);
let loc = def.lookup(db);
- let tree = loc.item_tree_id().item_tree(db);
- if let ItemContainerId::TraitId(trait_id) = loc.container {
- trait_vis(db, &resolver, trait_id)
- } else {
- Visibility::resolve(db, &resolver, &tree[tree[loc.id.value].visibility])
- }
+ let resolver = def.resolver(db);
+ trait_item_visibility(db, &resolver, loc.container).unwrap_or_else(|| {
+ let source = loc.source(db);
+ visibility_from_ast(db, &resolver, source.map(|src| src.visibility()))
+ })
}
/// Resolve visibility of a const.
pub(crate) fn const_visibility_query(db: &dyn DefDatabase, def: ConstId) -> Visibility {
- let resolver = def.resolver(db);
let loc = def.lookup(db);
- let tree = loc.item_tree_id().item_tree(db);
- if let ItemContainerId::TraitId(trait_id) = loc.container {
- trait_vis(db, &resolver, trait_id)
- } else {
- Visibility::resolve(db, &resolver, &tree[tree[loc.id.value].visibility])
- }
+ let resolver = def.resolver(db);
+ trait_item_visibility(db, &resolver, loc.container).unwrap_or_else(|| {
+ let source = loc.source(db);
+ visibility_from_ast(db, &resolver, source.map(|src| src.visibility()))
+ })
}
/// Resolve visibility of a type alias.
pub(crate) fn type_alias_visibility_query(db: &dyn DefDatabase, def: TypeAliasId) -> Visibility {
- let resolver = def.resolver(db);
let loc = def.lookup(db);
- let tree = loc.item_tree_id().item_tree(db);
- if let ItemContainerId::TraitId(trait_id) = loc.container {
- trait_vis(db, &resolver, trait_id)
- } else {
- Visibility::resolve(db, &resolver, &tree[tree[loc.id.value].visibility])
- }
+ let resolver = def.resolver(db);
+ trait_item_visibility(db, &resolver, loc.container).unwrap_or_else(|| {
+ let source = loc.source(db);
+ visibility_from_ast(db, &resolver, source.map(|src| src.visibility()))
+ })
}
-#[inline]
-fn trait_vis(db: &dyn DefDatabase, resolver: &Resolver<'_>, trait_id: TraitId) -> Visibility {
- let ItemLoc { id: tree_id, .. } = trait_id.lookup(db);
- let item_tree = tree_id.item_tree(db);
- let tr_def = &item_tree[tree_id.value];
- Visibility::resolve(db, resolver, &item_tree[tr_def.visibility])
+pub(crate) fn trait_visibility(
+ db: &dyn DefDatabase,
+ resolver: &Resolver<'_>,
+ def: TraitId,
+) -> Visibility {
+ let loc = def.lookup(db);
+ let source = loc.source(db);
+ visibility_from_ast(db, resolver, source.map(|src| src.visibility()))
}
diff --git a/crates/hir-expand/src/builtin/quote.rs b/crates/hir-expand/src/builtin/quote.rs
index 62b7b638e7..d5874f829b 100644
--- a/crates/hir-expand/src/builtin/quote.rs
+++ b/crates/hir-expand/src/builtin/quote.rs
@@ -277,8 +277,8 @@ mod tests {
assert_eq!(quoted.to_string(), "hello");
let t = format!("{quoted:#?}");
expect![[r#"
- SUBTREE $$ 937550:[email protected]#ROOT2024 937550:[email protected]#ROOT2024
- IDENT hello 937550:[email protected]#ROOT2024"#]]
+ SUBTREE $$ 937550:Root[0000, 0]@0..0#ROOT2024 937550:Root[0000, 0]@0..0#ROOT2024
+ IDENT hello 937550:Root[0000, 0]@0..0#ROOT2024"#]]
.assert_eq(&t);
}
diff --git a/crates/hir-expand/src/db.rs b/crates/hir-expand/src/db.rs
index 6fd9c497c1..7e9928c41f 100644
--- a/crates/hir-expand/src/db.rs
+++ b/crates/hir-expand/src/db.rs
@@ -60,6 +60,7 @@ pub trait ExpandDatabase: RootQueryDb {
fn proc_macros_for_crate(&self, krate: Crate) -> Option<Arc<CrateProcMacros>>;
#[salsa::invoke(ast_id_map)]
+ #[salsa::lru(1024)]
fn ast_id_map(&self, file_id: HirFileId) -> Arc<AstIdMap>;
#[salsa::transparent]
diff --git a/crates/hir-expand/src/files.rs b/crates/hir-expand/src/files.rs
index 8024823cbc..a73a22370d 100644
--- a/crates/hir-expand/src/files.rs
+++ b/crates/hir-expand/src/files.rs
@@ -106,7 +106,7 @@ impl FileRange {
/// It is stable across reparses, and can be used as salsa key/value.
pub type AstId<N> = crate::InFile<FileAstId<N>>;
-impl<N: AstIdNode> AstId<N> {
+impl<N: AstNode> AstId<N> {
pub fn to_node(&self, db: &dyn ExpandDatabase) -> N {
self.to_ptr(db).to_node(&db.parse_or_expand(self.file_id))
}
@@ -122,6 +122,13 @@ impl<N: AstIdNode> AstId<N> {
pub fn erase(&self) -> ErasedAstId {
crate::InFile::new(self.file_id, self.value.erase())
}
+ #[inline]
+ pub fn upcast<M: AstIdNode>(self) -> AstId<M>
+ where
+ N: Into<M>,
+ {
+ self.map(|it| it.upcast())
+ }
}
pub type ErasedAstId = crate::InFile<ErasedFileAstId>;
diff --git a/crates/hir-ty/src/chalk_db.rs b/crates/hir-ty/src/chalk_db.rs
index 22b96b55cb..710ac6e542 100644
--- a/crates/hir-ty/src/chalk_db.rs
+++ b/crates/hir-ty/src/chalk_db.rs
@@ -817,7 +817,7 @@ pub(crate) fn adt_datum_query(
.enum_variants(id)
.variants
.iter()
- .map(|&(variant_id, _)| variant_id_to_fields(variant_id.into()))
+ .map(|&(variant_id, _, _)| variant_id_to_fields(variant_id.into()))
.collect();
(rust_ir::AdtKind::Enum, variants)
}
diff --git a/crates/hir-ty/src/diagnostics/decl_check.rs b/crates/hir-ty/src/diagnostics/decl_check.rs
index 099100a732..fae129fddb 100644
--- a/crates/hir-ty/src/diagnostics/decl_check.rs
+++ b/crates/hir-ty/src/diagnostics/decl_check.rs
@@ -397,7 +397,7 @@ impl<'a> DeclValidator<'a> {
fn validate_enum_variants(&mut self, enum_id: EnumId) {
let data = self.db.enum_variants(enum_id);
- for (variant_id, _) in data.variants.iter() {
+ for (variant_id, _, _) in data.variants.iter() {
self.validate_enum_variant_fields(*variant_id);
}
@@ -405,7 +405,7 @@ impl<'a> DeclValidator<'a> {
let mut enum_variants_replacements = data
.variants
.iter()
- .filter_map(|(_, name)| {
+ .filter_map(|(_, name, _)| {
to_camel_case(&name.display_no_db(edition).to_smolstr()).map(|new_name| {
Replacement {
current_name: name.clone(),
diff --git a/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs b/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
index dd82a0f45c..0914b5aac5 100644
--- a/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
+++ b/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
@@ -465,7 +465,7 @@ impl PatCx for MatchCheckCtx<'_> {
ConstructorSet::NoConstructors
} else {
let mut variants = IndexVec::with_capacity(enum_data.variants.len());
- for &(variant, _) in enum_data.variants.iter() {
+ for &(variant, _, _) in enum_data.variants.iter() {
let is_uninhabited = is_enum_variant_uninhabited_from(
cx.db,
variant,
diff --git a/crates/hir-ty/src/drop.rs b/crates/hir-ty/src/drop.rs
index 70763759ef..b9b0f98286 100644
--- a/crates/hir-ty/src/drop.rs
+++ b/crates/hir-ty/src/drop.rs
@@ -71,7 +71,7 @@ pub(crate) fn has_drop_glue(db: &dyn HirDatabase, ty: Ty, env: Arc<TraitEnvironm
.enum_variants(id)
.variants
.iter()
- .map(|&(variant, _)| {
+ .map(|&(variant, _, _)| {
db.field_types(variant.into())
.iter()
.map(|(_, field_ty)| {
diff --git a/crates/hir-ty/src/inhabitedness.rs b/crates/hir-ty/src/inhabitedness.rs
index e81a5e3c31..8be812d8d5 100644
--- a/crates/hir-ty/src/inhabitedness.rs
+++ b/crates/hir-ty/src/inhabitedness.rs
@@ -115,7 +115,7 @@ impl UninhabitedFrom<'_> {
AdtId::EnumId(e) => {
let enum_data = self.db.enum_variants(e);
- for &(variant, _) in enum_data.variants.iter() {
+ for &(variant, _, _) in enum_data.variants.iter() {
let variant_inhabitedness = self.visit_variant(variant.into(), subst);
match variant_inhabitedness {
Break(VisiblyUninhabited) => (),
diff --git a/crates/hir-ty/src/layout/adt.rs b/crates/hir-ty/src/layout/adt.rs
index 3a020bf050..a886c33d15 100644
--- a/crates/hir-ty/src/layout/adt.rs
+++ b/crates/hir-ty/src/layout/adt.rs
@@ -60,7 +60,7 @@ pub fn layout_of_adt_query(
let r = variants
.variants
.iter()
- .map(|&(v, _)| handle_variant(v.into(), &db.variant_fields(v.into())))
+ .map(|&(v, _, _)| handle_variant(v.into(), &db.variant_fields(v.into())))
.collect::<Result<SmallVec<_>, _>>()?;
(r, db.enum_signature(e).repr.unwrap_or_default(), false)
}
diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs
index 21e5428520..8fb8d64779 100644
--- a/crates/hir-ty/src/mir/eval.rs
+++ b/crates/hir-ty/src/mir/eval.rs
@@ -2771,12 +2771,15 @@ impl Evaluator<'_> {
Err(e) => {
let db = self.db;
let loc = variant.lookup(db);
- let enum_loc = loc.parent.lookup(db);
let edition = self.crate_id.data(self.db).edition;
let name = format!(
"{}::{}",
- enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db, edition),
- loc.id.item_tree(db)[loc.id.value].name.display(db, edition),
+ self.db.enum_signature(loc.parent).name.display(db, edition),
+ self.db
+ .enum_variants(loc.parent)
+ .variant_name_by_id(variant)
+ .unwrap()
+ .display(db, edition),
);
Err(MirEvalError::ConstEvalError(name, Box::new(e)))
}
diff --git a/crates/hir-ty/src/mir/eval/shim.rs b/crates/hir-ty/src/mir/eval/shim.rs
index 90c52ee96f..512a275aa7 100644
--- a/crates/hir-ty/src/mir/eval/shim.rs
+++ b/crates/hir-ty/src/mir/eval/shim.rs
@@ -65,9 +65,7 @@ impl Evaluator<'_> {
Some(abi) => *abi == sym::rust_dash_intrinsic,
None => match def.lookup(self.db).container {
hir_def::ItemContainerId::ExternBlockId(block) => {
- let id = block.lookup(self.db).id;
- id.item_tree(self.db)[id.value].abi.as_ref()
- == Some(&sym::rust_dash_intrinsic)
+ self.db.extern_block_abi(block) == Some(sym::rust_dash_intrinsic)
}
_ => false,
},
@@ -87,8 +85,7 @@ impl Evaluator<'_> {
}
let is_extern_c = match def.lookup(self.db).container {
hir_def::ItemContainerId::ExternBlockId(block) => {
- let id = block.lookup(self.db).id;
- id.item_tree(self.db)[id.value].abi.as_ref() == Some(&sym::C)
+ self.db.extern_block_abi(block) == Some(sym::C)
}
_ => false,
};
diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs
index 99d9351530..ef1f215500 100644
--- a/crates/hir-ty/src/mir/lower.rs
+++ b/crates/hir-ty/src/mir/lower.rs
@@ -1922,11 +1922,14 @@ impl<'ctx> MirLowerCtx<'ctx> {
let edition = self.edition();
let db = self.db;
let loc = variant.lookup(db);
- let enum_loc = loc.parent.lookup(db);
let name = format!(
"{}::{}",
- enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db, edition),
- loc.id.item_tree(db)[loc.id.value].name.display(db, edition),
+ self.db.enum_signature(loc.parent).name.display(db, edition),
+ self.db
+ .enum_variants(loc.parent)
+ .variant_name_by_id(variant)
+ .unwrap()
+ .display(db, edition),
);
Err(MirLowerError::ConstEvalError(name.into(), Box::new(e)))
}
diff --git a/crates/hir-ty/src/mir/pretty.rs b/crates/hir-ty/src/mir/pretty.rs
index 7ae6e907e7..91dc2627d1 100644
--- a/crates/hir-ty/src/mir/pretty.rs
+++ b/crates/hir-ty/src/mir/pretty.rs
@@ -63,16 +63,15 @@ impl MirBody {
}
hir_def::DefWithBodyId::VariantId(id) => {
let loc = id.lookup(db);
- let enum_loc = loc.parent.lookup(db);
+ let edition = this.display_target.edition;
w!(
this,
"enum {}::{} = ",
- enum_loc.id.item_tree(db)[enum_loc.id.value]
- .name
- .display(db, this.display_target.edition),
- loc.id.item_tree(db)[loc.id.value]
- .name
- .display(db, this.display_target.edition),
+ db.enum_signature(loc.parent).name.display(db, edition),
+ db.enum_variants(loc.parent)
+ .variant_name_by_id(id)
+ .unwrap()
+ .display(db, edition),
)
}
});
diff --git a/crates/hir-ty/src/tests.rs b/crates/hir-ty/src/tests.rs
index 2b75bd6f16..48af7b2e32 100644
--- a/crates/hir-ty/src/tests.rs
+++ b/crates/hir-ty/src/tests.rs
@@ -479,7 +479,7 @@ pub(crate) fn visit_module(
visit_body(db, &body, cb);
}
ModuleDefId::AdtId(hir_def::AdtId::EnumId(it)) => {
- db.enum_variants(it).variants.iter().for_each(|&(it, _)| {
+ db.enum_variants(it).variants.iter().for_each(|&(it, _, _)| {
let body = db.body(it.into());
cb(it.into());
visit_body(db, &body, cb);
diff --git a/crates/hir-ty/src/tests/incremental.rs b/crates/hir-ty/src/tests/incremental.rs
index 6ac260ac76..a055ef879d 100644
--- a/crates/hir-ty/src/tests/incremental.rs
+++ b/crates/hir-ty/src/tests/incremental.rs
@@ -353,6 +353,7 @@ impl SomeStruct {
"impl_self_ty_with_diagnostics_shim".to_owned(),
"struct_signature_shim".to_owned(),
"struct_signature_with_source_map_shim".to_owned(),
+ "attrs_shim".to_owned(),
"type_for_adt_tracked".to_owned(),
];
@@ -442,6 +443,6 @@ fn main() {
let _inference_result = db.infer(def);
}
});
- assert!(format!("{events:?}").contains("trait_solve_shim"))
+ assert!(!format!("{events:?}").contains("trait_solve_shim"))
}
}
diff --git a/crates/hir-ty/src/utils.rs b/crates/hir-ty/src/utils.rs
index 1e0ff423de..f797e60b05 100644
--- a/crates/hir-ty/src/utils.rs
+++ b/crates/hir-ty/src/utils.rs
@@ -293,9 +293,7 @@ pub fn is_fn_unsafe_to_call(
let loc = func.lookup(db);
match loc.container {
hir_def::ItemContainerId::ExternBlockId(block) => {
- let id = block.lookup(db).id;
- let is_intrinsic_block =
- id.item_tree(db)[id.value].abi.as_ref() == Some(&sym::rust_dash_intrinsic);
+ let is_intrinsic_block = db.extern_block_abi(block) == Some(sym::rust_dash_intrinsic);
if is_intrinsic_block {
// legacy intrinsics
// extern "rust-intrinsic" intrinsics are unsafe unless they have the rustc_safe_intrinsic attribute
diff --git a/crates/hir-ty/src/variance.rs b/crates/hir-ty/src/variance.rs
index d6b43aeed4..62478d4fd8 100644
--- a/crates/hir-ty/src/variance.rs
+++ b/crates/hir-ty/src/variance.rs
@@ -213,7 +213,7 @@ impl Context<'_> {
AdtId::StructId(s) => add_constraints_from_variant(VariantId::StructId(s)),
AdtId::UnionId(u) => add_constraints_from_variant(VariantId::UnionId(u)),
AdtId::EnumId(e) => {
- db.enum_variants(e).variants.iter().for_each(|&(variant, _)| {
+ db.enum_variants(e).variants.iter().for_each(|&(variant, _, _)| {
add_constraints_from_variant(VariantId::EnumVariantId(variant))
});
}
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 969fd3eb48..c746b88c5b 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -52,12 +52,14 @@ use hir_def::{
BindingAnnotation, BindingId, Expr, ExprId, ExprOrPatId, LabelId, Pat,
generics::{LifetimeParamData, TypeOrConstParamData, TypeParamProvenance},
},
- item_tree::{AttrOwner, FieldParent, ImportAlias, ItemTreeFieldId, ItemTreeNode},
+ item_tree::ImportAlias,
layout::{self, ReprOptions, TargetDataLayout},
nameres::{self, diagnostics::DefDiagnostic},
per_ns::PerNs,
resolver::{HasResolver, Resolver},
signatures::{ImplFlags, StaticFlags, TraitFlags, VariantFields},
+ src::HasSource as _,
+ visibility::visibility_from_ast,
};
use hir_expand::{
AstId, MacroCallKind, RenderedExpandError, ValueResult, attrs::collect_attrs,
@@ -81,11 +83,11 @@ use itertools::Itertools;
use nameres::diagnostics::DefDiagnosticKind;
use rustc_hash::FxHashSet;
use smallvec::SmallVec;
-use span::{Edition, FileId};
+use span::{AstIdNode, Edition, FileId};
use stdx::{format_to, impl_from, never};
use syntax::{
AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, T, TextRange, ToSmolStr,
- ast::{self, HasAttrs as _, HasName},
+ ast::{self, HasAttrs as _, HasName, HasVisibility as _},
format_smolstr,
};
use triomphe::{Arc, ThinArc};
@@ -687,7 +689,7 @@ impl Module {
let source_map = db.enum_signature_with_source_map(e.id).1;
expr_store_diagnostics(db, acc, &source_map);
let (variants, diagnostics) = db.enum_variants_with_diagnostics(e.id);
- let file = e.id.lookup(db).id.file_id();
+ let file = e.id.lookup(db).id.file_id;
let ast_id_map = db.ast_id_map(file);
if let Some(diagnostics) = &diagnostics {
for diag in diagnostics.iter() {
@@ -704,7 +706,7 @@ impl Module {
);
}
}
- for &(v, _) in &variants.variants {
+ for &(v, _, _) in &variants.variants {
let source_map = db.variant_fields_with_source_map(v.into()).1;
push_ty_diagnostics(
db,
@@ -742,12 +744,10 @@ impl Module {
GenericDef::Impl(impl_def).diagnostics(db, acc);
let loc = impl_def.id.lookup(db);
- let tree = loc.id.item_tree(db);
let source_map = db.impl_signature_with_source_map(impl_def.id).1;
expr_store_diagnostics(db, acc, &source_map);
- let node = &tree[loc.id.value];
- let file_id = loc.id.file_id();
+ let file_id = loc.id.file_id;
if file_id.macro_file().is_some_and(|it| it.kind(db) == MacroKind::DeriveBuiltIn) {
// these expansion come from us, diagnosing them is a waste of resources
// FIXME: Once we diagnose the inputs to builtin derives, we should at least extract those diagnostics somehow
@@ -765,11 +765,11 @@ impl Module {
}
if inherent_impls.invalid_impls().contains(&impl_def.id) {
- acc.push(IncoherentImpl { impl_: ast_id_map.get(node.ast_id()), file_id }.into())
+ acc.push(IncoherentImpl { impl_: ast_id_map.get(loc.id.value), file_id }.into())
}
if !impl_def.check_orphan_rules(db) {
- acc.push(TraitImplOrphan { impl_: ast_id_map.get(node.ast_id()), file_id }.into())
+ acc.push(TraitImplOrphan { impl_: ast_id_map.get(loc.id.value), file_id }.into())
}
let trait_ = impl_def.trait_(db);
@@ -808,11 +808,11 @@ impl Module {
// unsafe negative impl
(true, _, true, _) |
// unsafe impl for safe trait
- (true, false, _, false) => acc.push(TraitImplIncorrectSafety { impl_: ast_id_map.get(node.ast_id()), file_id, should_be_safe: true }.into()),
+ (true, false, _, false) => acc.push(TraitImplIncorrectSafety { impl_: ast_id_map.get(loc.id.value), file_id, should_be_safe: true }.into()),
// safe impl for unsafe trait
(false, true, false, _) |
// safe impl of dangling drop
- (false, false, _, true) => acc.push(TraitImplIncorrectSafety { impl_: ast_id_map.get(node.ast_id()), file_id, should_be_safe: false }.into()),
+ (false, false, _, true) => acc.push(TraitImplIncorrectSafety { impl_: ast_id_map.get(loc.id.value), file_id, should_be_safe: false }.into()),
_ => (),
};
@@ -839,7 +839,7 @@ impl Module {
TraitImplRedundantAssocItems {
trait_,
file_id,
- impl_: ast_id_map.get(node.ast_id()),
+ impl_: ast_id_map.get(loc.id.value),
assoc_item: (name, assoc_item),
}
.into(),
@@ -889,7 +889,7 @@ impl Module {
if !missing.is_empty() {
acc.push(
TraitImplMissingAssocItems {
- impl_: ast_id_map.get(node.ast_id()),
+ impl_: ast_id_map.get(loc.id.value),
file_id,
missing,
}
@@ -1076,73 +1076,25 @@ fn emit_def_diagnostic_(
)
}
DefDiagnosticKind::UnresolvedImport { id, index } => {
- let file_id = id.file_id();
- let item_tree = id.item_tree(db);
- let import = &item_tree[id.value];
+ let file_id = id.file_id;
- let use_tree = import.use_tree_to_ast(db, file_id, *index);
+ let use_tree = hir_def::src::use_tree_to_ast(db, *id, *index);
acc.push(
UnresolvedImport { decl: InFile::new(file_id, AstPtr::new(&use_tree)) }.into(),
);
}
- DefDiagnosticKind::UnconfiguredCode { tree, item, cfg, opts } => {
- let item_tree = tree.item_tree(db);
- let ast_id_map = db.ast_id_map(tree.file_id());
- // FIXME: This parses... We could probably store relative ranges for the children things
- // here in the item tree?
- (|| {
- let process_field_list =
- |field_list: Option<_>, idx: ItemTreeFieldId| match field_list? {
- ast::FieldList::RecordFieldList(it) => Some(SyntaxNodePtr::new(
- it.fields().nth(idx.into_raw().into_u32() as usize)?.syntax(),
- )),
- ast::FieldList::TupleFieldList(it) => Some(SyntaxNodePtr::new(
- it.fields().nth(idx.into_raw().into_u32() as usize)?.syntax(),
- )),
- };
- let ptr = match *item {
- AttrOwner::ModItem(it) => {
- ast_id_map.get(it.ast_id(&item_tree)).syntax_node_ptr()
- }
- AttrOwner::TopLevel => ast_id_map.root(),
- AttrOwner::Variant(it) => {
- ast_id_map.get(item_tree[it].ast_id).syntax_node_ptr()
- }
- AttrOwner::Field(FieldParent::EnumVariant(parent), idx) => process_field_list(
- ast_id_map
- .get(item_tree[parent].ast_id)
- .to_node(&db.parse_or_expand(tree.file_id()))
- .field_list(),
- idx,
- )?,
- AttrOwner::Field(FieldParent::Struct(parent), idx) => process_field_list(
- ast_id_map
- .get(item_tree[parent.index()].ast_id)
- .to_node(&db.parse_or_expand(tree.file_id()))
- .field_list(),
- idx,
- )?,
- AttrOwner::Field(FieldParent::Union(parent), idx) => SyntaxNodePtr::new(
- ast_id_map
- .get(item_tree[parent.index()].ast_id)
- .to_node(&db.parse_or_expand(tree.file_id()))
- .record_field_list()?
- .fields()
- .nth(idx.into_raw().into_u32() as usize)?
- .syntax(),
- ),
- };
- acc.push(
- InactiveCode {
- node: InFile::new(tree.file_id(), ptr),
- cfg: cfg.clone(),
- opts: opts.clone(),
- }
- .into(),
- );
- Some(())
- })();
+ DefDiagnosticKind::UnconfiguredCode { ast_id, cfg, opts } => {
+ let ast_id_map = db.ast_id_map(ast_id.file_id);
+ let ptr = ast_id_map.get_erased(ast_id.value);
+ acc.push(
+ InactiveCode {
+ node: InFile::new(ast_id.file_id, ptr),
+ cfg: cfg.clone(),
+ opts: opts.clone(),
+ }
+ .into(),
+ );
}
DefDiagnosticKind::UnresolvedMacroCall { ast, path } => {
let (node, precise_location) = precise_macro_call_location(ast, db);
@@ -1478,12 +1430,8 @@ impl Struct {
impl HasVisibility for Struct {
fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
let loc = self.id.lookup(db);
- let item_tree = loc.id.item_tree(db);
- Visibility::resolve(
- db,
- &self.id.resolver(db),
- &item_tree[item_tree[loc.id.value].visibility],
- )
+ let source = loc.source(db);
+ visibility_from_ast(db, &self.id.resolver(db), source.map(|src| src.visibility()))
}
}
@@ -1536,12 +1484,8 @@ impl Union {
impl HasVisibility for Union {
fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
let loc = self.id.lookup(db);
- let item_tree = loc.id.item_tree(db);
- Visibility::resolve(
- db,
- &self.id.resolver(db),
- &item_tree[item_tree[loc.id.value].visibility],
- )
+ let source = loc.source(db);
+ visibility_from_ast(db, &self.id.resolver(db), source.map(|src| src.visibility()))
}
}
@@ -1560,7 +1504,7 @@ impl Enum {
}
pub fn variants(self, db: &dyn HirDatabase) -> Vec<Variant> {
- db.enum_variants(self.id).variants.iter().map(|&(id, _)| Variant { id }).collect()
+ db.enum_variants(self.id).variants.iter().map(|&(id, _, _)| Variant { id }).collect()
}
pub fn num_variants(self, db: &dyn HirDatabase) -> usize {
@@ -1629,12 +1573,8 @@ impl Enum {
impl HasVisibility for Enum {
fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
let loc = self.id.lookup(db);
- let item_tree = loc.id.item_tree(db);
- Visibility::resolve(
- db,
- &self.id.resolver(db),
- &item_tree[item_tree[loc.id.value].visibility],
- )
+ let source = loc.source(db);
+ visibility_from_ast(db, &self.id.resolver(db), source.map(|src| src.visibility()))
}
}
@@ -2708,10 +2648,9 @@ impl ExternCrateDecl {
pub fn resolved_crate(self, db: &dyn HirDatabase) -> Option<Crate> {
let loc = self.id.lookup(db);
- let item_tree = loc.id.item_tree(db);
let krate = loc.container.krate();
- let name = &item_tree[loc.id.value].name;
- if *name == sym::self_ {
+ let name = self.name(db);
+ if name == sym::self_ {
Some(krate.into())
} else {
krate.data(db).dependencies.iter().find_map(|dep| {
@@ -2722,25 +2661,29 @@ impl ExternCrateDecl {
pub fn name(self, db: &dyn HirDatabase) -> Name {
let loc = self.id.lookup(db);
- let item_tree = loc.id.item_tree(db);
- item_tree[loc.id.value].name.clone()
+ let source = loc.source(db);
+ as_name_opt(source.value.name_ref())
}
pub fn alias(self, db: &dyn HirDatabase) -> Option<ImportAlias> {
let loc = self.id.lookup(db);
- let item_tree = loc.id.item_tree(db);
- item_tree[loc.id.value].alias.clone()
+ let source = loc.source(db);
+ let rename = source.value.rename()?;
+ if let Some(name) = rename.name() {
+ Some(ImportAlias::Alias(name.as_name()))
+ } else if rename.underscore_token().is_some() {
+ Some(ImportAlias::Underscore)
+ } else {
+ None
+ }
}
/// Returns the name under which this crate is made accessible, taking `_` into account.
pub fn alias_or_name(self, db: &dyn HirDatabase) -> Option<Name> {
- let loc = self.id.lookup(db);
- let item_tree = loc.id.item_tree(db);
-
- match &item_tree[loc.id.value].alias {
+ match self.alias(db) {
Some(ImportAlias::Underscore) => None,
- Some(ImportAlias::Alias(alias)) => Some(alias.clone()),
- None => Some(item_tree[loc.id.value].name.clone()),
+ Some(ImportAlias::Alias(alias)) => Some(alias),
+ None => Some(self.name(db)),
}
}
}
@@ -2748,12 +2691,8 @@ impl ExternCrateDecl {
impl HasVisibility for ExternCrateDecl {
fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
let loc = self.id.lookup(db);
- let item_tree = loc.id.item_tree(db);
- Visibility::resolve(
- db,
- &self.id.resolver(db),
- &item_tree[item_tree[loc.id.value].visibility],
- )
+ let source = loc.source(db);
+ visibility_from_ast(db, &self.id.resolver(db), source.map(|src| src.visibility()))
}
}
@@ -2873,12 +2812,8 @@ impl Static {
impl HasVisibility for Static {
fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
let loc = self.id.lookup(db);
- let item_tree = loc.id.item_tree(db);
- Visibility::resolve(
- db,
- &self.id.resolver(db),
- &item_tree[item_tree[loc.id.value].visibility],
- )
+ let source = loc.source(db);
+ visibility_from_ast(db, &self.id.resolver(db), source.map(|src| src.visibility()))
}
}
@@ -2967,11 +2902,7 @@ impl Trait {
}
fn all_macro_calls(&self, db: &dyn HirDatabase) -> Box<[(AstId<ast::Item>, MacroCallId)]> {
- db.trait_items(self.id)
- .macro_calls
- .as_ref()
- .map(|it| it.as_ref().clone().into_boxed_slice())
- .unwrap_or_default()
+ db.trait_items(self.id).macro_calls.to_vec().into_boxed_slice()
}
/// `#[rust_analyzer::completions(...)]` mode.
@@ -2983,12 +2914,8 @@ impl Trait {
impl HasVisibility for Trait {
fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
let loc = self.id.lookup(db);
- let item_tree = loc.id.item_tree(db);
- Visibility::resolve(
- db,
- &self.id.resolver(db),
- &item_tree[item_tree[loc.id.value].visibility],
- )
+ let source = loc.source(db);
+ visibility_from_ast(db, &self.id.resolver(db), source.map(|src| src.visibility()))
}
}
@@ -3010,12 +2937,8 @@ impl TraitAlias {
impl HasVisibility for TraitAlias {
fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
let loc = self.id.lookup(db);
- let item_tree = loc.id.item_tree(db);
- Visibility::resolve(
- db,
- &self.id.resolver(db),
- &item_tree[item_tree[loc.id.value].visibility],
- )
+ let source = loc.source(db);
+ visibility_from_ast(db, &self.id.resolver(db), source.map(|src| src.visibility()))
}
}
@@ -3163,25 +3086,23 @@ impl Macro {
match self.id {
MacroId::Macro2Id(id) => {
let loc = id.lookup(db);
- let item_tree = loc.id.item_tree(db);
- item_tree[loc.id.value].name.clone()
+ let source = loc.source(db);
+ as_name_opt(source.value.name())
}
MacroId::MacroRulesId(id) => {
let loc = id.lookup(db);
- let item_tree = loc.id.item_tree(db);
- item_tree[loc.id.value].name.clone()
+ let source = loc.source(db);
+ as_name_opt(source.value.name())
}
MacroId::ProcMacroId(id) => {
let loc = id.lookup(db);
- let item_tree = loc.id.item_tree(db);
+ let source = loc.source(db);
match loc.kind {
ProcMacroKind::CustomDerive => db
.attrs(id.into())
.parse_proc_macro_derive()
- .map_or_else(|| item_tree[loc.id.value].name.clone(), |(it, _)| it),
- ProcMacroKind::Bang | ProcMacroKind::Attr => {
- item_tree[loc.id.value].name.clone()
- }
+ .map_or_else(|| as_name_opt(source.value.name()), |(it, _)| it),
+ ProcMacroKind::Bang | ProcMacroKind::Attr => as_name_opt(source.value.name()),
}
}
}
@@ -3278,12 +3199,8 @@ impl HasVisibility for Macro {
match self.id {
MacroId::Macro2Id(id) => {
let loc = id.lookup(db);
- let item_tree = loc.id.item_tree(db);
- Visibility::resolve(
- db,
- &id.resolver(db),
- &item_tree[item_tree[loc.id.value].visibility],
- )
+ let source = loc.source(db);
+ visibility_from_ast(db, &id.resolver(db), source.map(|src| src.visibility()))
}
MacroId::MacroRulesId(_) => Visibility::Public,
MacroId::ProcMacroId(_) => Visibility::Public,
@@ -3437,7 +3354,7 @@ fn as_assoc_item<'db, ID, DEF, LOC>(
where
ID: Lookup<Database = dyn DefDatabase, Data = AssocItemLoc<LOC>>,
DEF: From<ID>,
- LOC: ItemTreeNode,
+ LOC: AstIdNode,
{
match id.lookup(db).container {
ItemContainerId::TraitId(_) | ItemContainerId::ImplId(_) => Some(ctor(DEF::from(id))),
@@ -3453,7 +3370,7 @@ fn as_extern_assoc_item<'db, ID, DEF, LOC>(
where
ID: Lookup<Database = dyn DefDatabase, Data = AssocItemLoc<LOC>>,
DEF: From<ID>,
- LOC: ItemTreeNode,
+ LOC: AstIdNode,
{
match id.lookup(db).container {
ItemContainerId::ExternBlockId(_) => Some(ctor(DEF::from(id))),
@@ -4545,11 +4462,7 @@ impl Impl {
}
fn all_macro_calls(&self, db: &dyn HirDatabase) -> Box<[(AstId<ast::Item>, MacroCallId)]> {
- db.impl_items(self.id)
- .macro_calls
- .as_ref()
- .map(|it| it.as_ref().clone().into_boxed_slice())
- .unwrap_or_default()
+ db.impl_items(self.id).macro_calls.to_vec().into_boxed_slice()
}
}
@@ -6510,3 +6423,7 @@ pub fn resolve_absolute_path<'a, I: Iterator<Item = Symbol> + Clone + 'a>(
})
.flatten()
}
+
+fn as_name_opt(name: Option<impl AsName>) -> Name {
+ name.map_or_else(Name::missing, |name| name.as_name())
+}
diff --git a/crates/hir/src/semantics/child_by_source.rs b/crates/hir/src/semantics/child_by_source.rs
index 1a6d63c88c..ea44451a8e 100644
--- a/crates/hir/src/semantics/child_by_source.rs
+++ b/crates/hir/src/semantics/child_by_source.rs
@@ -6,10 +6,11 @@
use either::Either;
use hir_expand::{HirFileId, attrs::collect_attrs};
+use span::AstIdNode;
use syntax::{AstPtr, ast};
use hir_def::{
- AdtId, AssocItemId, DefWithBodyId, EnumId, FieldId, GenericDefId, ImplId, ItemTreeLoc,
+ AdtId, AssocItemId, AstIdLoc, DefWithBodyId, EnumId, FieldId, GenericDefId, ImplId,
LifetimeParamId, Lookup, MacroId, ModuleDefId, ModuleId, TraitId, TypeOrConstParamId,
VariantId,
db::DefDatabase,
@@ -19,7 +20,6 @@ use hir_def::{
},
hir::generics::GenericParams,
item_scope::ItemScope,
- item_tree::ItemTreeNode,
nameres::DefMap,
src::{HasChildSource, HasSource},
};
@@ -113,7 +113,7 @@ impl ChildBySource for ItemScope {
ids.iter().for_each(|&id| {
if let MacroId::MacroRulesId(id) = id {
let loc = id.lookup(db);
- if loc.id.file_id() == file_id {
+ if loc.id.file_id == file_id {
res[keys::MACRO_RULES].insert(loc.ast_ptr(db).value, id);
}
}
@@ -199,16 +199,14 @@ impl ChildBySource for VariantId {
impl ChildBySource for EnumId {
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() {
+ 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 ast_id_map = db.ast_id_map(loc.id.file_id);
- db.enum_variants(*self).variants.iter().for_each(|&(variant, _)| {
- res[keys::ENUM_VARIANT]
- .insert(ast_id_map.get(tree[variant.lookup(db).id.value].ast_id), variant);
+ db.enum_variants(*self).variants.iter().for_each(|&(variant, _, _)| {
+ res[keys::ENUM_VARIANT].insert(ast_id_map.get(variant.lookup(db).id.value), variant);
});
let (_, source_map) = db.enum_signature_with_source_map(*self);
source_map
@@ -287,15 +285,14 @@ fn insert_item_loc<ID, N, Data>(
res: &mut DynMap,
file_id: HirFileId,
id: ID,
- key: Key<N::Source, ID>,
+ key: Key<N, ID>,
) where
ID: Lookup<Database = dyn DefDatabase, Data = Data> + 'static,
- Data: ItemTreeLoc<Id = N>,
- N: ItemTreeNode,
- N::Source: 'static,
+ Data: AstIdLoc<Ast = N>,
+ N: AstIdNode + 'static,
{
let loc = id.lookup(db);
- if loc.item_tree_id().file_id() == file_id {
+ if loc.ast_id().file_id == file_id {
res[key].insert(loc.ast_ptr(db).value, id)
}
}
diff --git a/crates/mbe/src/tests.rs b/crates/mbe/src/tests.rs
index 769455faac..56034516ef 100644
--- a/crates/mbe/src/tests.rs
+++ b/crates/mbe/src/tests.rs
@@ -3,7 +3,9 @@
// FIXME: Move more of the nameres independent tests from
// crates\hir-def\src\macro_expansion_tests\mod.rs to this
use expect_test::expect;
-use span::{Edition, EditionedFileId, ErasedFileAstId, FileId, Span, SpanAnchor, SyntaxContext};
+use span::{
+ Edition, EditionedFileId, FileId, ROOT_ERASED_FILE_AST_ID, Span, SpanAnchor, SyntaxContext,
+};
use stdx::format_to;
use tt::{TextRange, TextSize};
@@ -24,7 +26,7 @@ fn check_(
def_edition,
SpanAnchor {
file_id: EditionedFileId::new(FileId::from_raw(0), def_edition),
- ast_id: ErasedFileAstId::from_raw(0),
+ ast_id: ROOT_ERASED_FILE_AST_ID,
},
SyntaxContext::root(Edition::CURRENT),
decl,
@@ -37,7 +39,7 @@ fn check_(
};
let call_anchor = SpanAnchor {
file_id: EditionedFileId::new(FileId::from_raw(1), call_edition),
- ast_id: ErasedFileAstId::from_raw(0),
+ ast_id: ROOT_ERASED_FILE_AST_ID,
};
let arg_tt = syntax_bridge::parse_to_token_tree(
call_edition,
@@ -110,8 +112,8 @@ fn unbalanced_brace() {
"#,
r#""#,
expect![[r#"
- SUBTREE $$ 1:[email protected]#ROOT2024 1:[email protected]#ROOT2024
- SUBTREE {} 0:[email protected]#ROOT2024 0:[email protected]#ROOT2024
+ SUBTREE $$ 1:Root[0000, 0]@0..0#ROOT2024 1:Root[0000, 0]@0..0#ROOT2024
+ SUBTREE {} 0:Root[0000, 0]@9..10#ROOT2024 0:Root[0000, 0]@11..12#ROOT2024
{}"#]],
);
@@ -133,25 +135,25 @@ fn token_mapping_smoke_test() {
struct MyTraitMap2
"#,
expect![[r#"
- SUBTREE $$ 1:[email protected]#ROOT2024 1:[email protected]#ROOT2024
- IDENT struct 0:[email protected]#ROOT2024
- IDENT MyTraitMap2 1:[email protected]#ROOT2024
- SUBTREE {} 0:[email protected]#ROOT2024 0:[email protected]#ROOT2024
- IDENT map 0:[email protected]#ROOT2024
- PUNCH : [alone] 0:[email protected]#ROOT2024
- PUNCH : [joint] 0:[email protected]#ROOT2024
- PUNCH : [alone] 0:[email protected]#ROOT2024
- IDENT std 0:[email protected]#ROOT2024
- PUNCH : [joint] 0:[email protected]#ROOT2024
- PUNCH : [alone] 0:[email protected]#ROOT2024
- IDENT collections 0:[email protected]#ROOT2024
- PUNCH : [joint] 0:[email protected]#ROOT2024
- PUNCH : [alone] 0:[email protected]#ROOT2024
- IDENT HashSet 0:[email protected]#ROOT2024
- PUNCH < [alone] 0:[email protected]#ROOT2024
- SUBTREE () 0:[email protected]#ROOT2024 0:[email protected]#ROOT2024
- PUNCH > [joint] 0:[email protected]#ROOT2024
- PUNCH , [alone] 0:[email protected]#ROOT2024
+ SUBTREE $$ 1:Root[0000, 0]@0..20#ROOT2024 1:Root[0000, 0]@0..20#ROOT2024
+ IDENT struct 0:Root[0000, 0]@34..40#ROOT2024
+ IDENT MyTraitMap2 1:Root[0000, 0]@8..19#ROOT2024
+ SUBTREE {} 0:Root[0000, 0]@48..49#ROOT2024 0:Root[0000, 0]@100..101#ROOT2024
+ IDENT map 0:Root[0000, 0]@58..61#ROOT2024
+ PUNCH : [alone] 0:Root[0000, 0]@61..62#ROOT2024
+ PUNCH : [joint] 0:Root[0000, 0]@63..64#ROOT2024
+ PUNCH : [alone] 0:Root[0000, 0]@64..65#ROOT2024
+ IDENT std 0:Root[0000, 0]@65..68#ROOT2024
+ PUNCH : [joint] 0:Root[0000, 0]@68..69#ROOT2024
+ PUNCH : [alone] 0:Root[0000, 0]@69..70#ROOT2024
+ IDENT collections 0:Root[0000, 0]@70..81#ROOT2024
+ PUNCH : [joint] 0:Root[0000, 0]@81..82#ROOT2024
+ PUNCH : [alone] 0:Root[0000, 0]@82..83#ROOT2024
+ IDENT HashSet 0:Root[0000, 0]@83..90#ROOT2024
+ PUNCH < [alone] 0:Root[0000, 0]@90..91#ROOT2024
+ SUBTREE () 0:Root[0000, 0]@91..92#ROOT2024 0:Root[0000, 0]@92..93#ROOT2024
+ PUNCH > [joint] 0:Root[0000, 0]@93..94#ROOT2024
+ PUNCH , [alone] 0:Root[0000, 0]@94..95#ROOT2024
struct MyTraitMap2 {
map: ::std::collections::HashSet<()>,
@@ -180,28 +182,28 @@ fn main() {
}
"#,
expect![[r#"
- SUBTREE $$ 1:[email protected]#ROOT2024 1:[email protected]#ROOT2024
- IDENT fn 1:[email protected]#ROOT2024
- IDENT main 1:[email protected]#ROOT2024
- SUBTREE () 1:[email protected]#ROOT2024 1:[email protected]#ROOT2024
- SUBTREE {} 1:[email protected]#ROOT2024 1:[email protected]#ROOT2024
- LITERAL Integer 1 1:[email protected]#ROOT2024
- PUNCH ; [alone] 1:[email protected]#ROOT2024
- LITERAL Float 1.0 1:[email protected]#ROOT2024
- PUNCH ; [alone] 1:[email protected]#ROOT2024
- SUBTREE () 1:[email protected]#ROOT2024 1:[email protected]#ROOT2024
- SUBTREE () 1:[email protected]#ROOT2024 1:[email protected]#ROOT2024
- LITERAL Integer 1 1:[email protected]#ROOT2024
- PUNCH , [alone] 1:[email protected]#ROOT2024
- PUNCH , [alone] 1:[email protected]#ROOT2024
- PUNCH . [alone] 1:[email protected]#ROOT2024
- LITERAL Float 0.0 1:[email protected]#ROOT2024
- PUNCH ; [alone] 1:[email protected]#ROOT2024
- IDENT let 1:[email protected]#ROOT2024
- IDENT x 1:[email protected]#ROOT2024
- PUNCH = [alone] 1:[email protected]#ROOT2024
- LITERAL Integer 1 1:[email protected]#ROOT2024
- PUNCH ; [alone] 1:[email protected]#ROOT2024
+ SUBTREE $$ 1:Root[0000, 0]@0..63#ROOT2024 1:Root[0000, 0]@0..63#ROOT2024
+ IDENT fn 1:Root[0000, 0]@1..3#ROOT2024
+ IDENT main 1:Root[0000, 0]@4..8#ROOT2024
+ SUBTREE () 1:Root[0000, 0]@8..9#ROOT2024 1:Root[0000, 0]@9..10#ROOT2024
+ SUBTREE {} 1:Root[0000, 0]@11..12#ROOT2024 1:Root[0000, 0]@61..62#ROOT2024
+ LITERAL Integer 1 1:Root[0000, 0]@17..18#ROOT2024
+ PUNCH ; [alone] 1:Root[0000, 0]@18..19#ROOT2024
+ LITERAL Float 1.0 1:Root[0000, 0]@24..27#ROOT2024
+ PUNCH ; [alone] 1:Root[0000, 0]@27..28#ROOT2024
+ SUBTREE () 1:Root[0000, 0]@33..34#ROOT2024 1:Root[0000, 0]@39..40#ROOT2024
+ SUBTREE () 1:Root[0000, 0]@34..35#ROOT2024 1:Root[0000, 0]@37..38#ROOT2024
+ LITERAL Integer 1 1:Root[0000, 0]@35..36#ROOT2024
+ PUNCH , [alone] 1:Root[0000, 0]@36..37#ROOT2024
+ PUNCH , [alone] 1:Root[0000, 0]@38..39#ROOT2024
+ PUNCH . [alone] 1:Root[0000, 0]@40..41#ROOT2024
+ LITERAL Float 0.0 1:Root[0000, 0]@41..44#ROOT2024
+ PUNCH ; [alone] 1:Root[0000, 0]@44..45#ROOT2024
+ IDENT let 1:Root[0000, 0]@50..53#ROOT2024
+ IDENT x 1:Root[0000, 0]@54..55#ROOT2024
+ PUNCH = [alone] 1:Root[0000, 0]@56..57#ROOT2024
+ LITERAL Integer 1 1:Root[0000, 0]@58..59#ROOT2024
+ PUNCH ; [alone] 1:Root[0000, 0]@59..60#ROOT2024
fn main(){
1;
@@ -227,14 +229,14 @@ fn expr_2021() {
const { 1 },
"#,
expect![[r#"
- SUBTREE $$ 1:[email protected]#ROOT2024 1:[email protected]#ROOT2024
- IDENT _ 1:[email protected]#ROOT2024
- PUNCH ; [joint] 0:[email protected]#ROOT2024
- SUBTREE () 0:[email protected]#ROOT2024 0:[email protected]#ROOT2024
- IDENT const 1:[email protected]#ROOT2024
- SUBTREE {} 1:[email protected]#ROOT2024 1:[email protected]#ROOT2024
- LITERAL Integer 1 1:[email protected]#ROOT2024
- PUNCH ; [alone] 0:[email protected]#ROOT2024
+ SUBTREE $$ 1:Root[0000, 0]@0..25#ROOT2024 1:Root[0000, 0]@0..25#ROOT2024
+ IDENT _ 1:Root[0000, 0]@5..6#ROOT2024
+ PUNCH ; [joint] 0:Root[0000, 0]@36..37#ROOT2024
+ SUBTREE () 0:Root[0000, 0]@34..35#ROOT2024 0:Root[0000, 0]@34..35#ROOT2024
+ IDENT const 1:Root[0000, 0]@12..17#ROOT2024
+ SUBTREE {} 1:Root[0000, 0]@18..19#ROOT2024 1:Root[0000, 0]@22..23#ROOT2024
+ LITERAL Integer 1 1:Root[0000, 0]@20..21#ROOT2024
+ PUNCH ; [alone] 0:Root[0000, 0]@39..40#ROOT2024
_;
(const {
@@ -255,13 +257,13 @@ fn expr_2021() {
expect![[r#"
ExpandError {
inner: (
- 1:[email protected]#ROOT2024,
+ 1:Root[0000, 0]@5..6#ROOT2024,
NoMatchingRule,
),
}
- SUBTREE $$ 1:[email protected]#ROOT2024 1:[email protected]#ROOT2024
- PUNCH ; [alone] 0:[email protected]#ROOT2024
+ SUBTREE $$ 1:Root[0000, 0]@0..8#ROOT2024 1:Root[0000, 0]@0..8#ROOT2024
+ PUNCH ; [alone] 0:Root[0000, 0]@39..40#ROOT2024
;"#]],
);
@@ -279,13 +281,13 @@ fn expr_2021() {
expect![[r#"
ExpandError {
inner: (
- 1:[email protected]#ROOT2024,
+ 1:Root[0000, 0]@5..10#ROOT2024,
NoMatchingRule,
),
}
- SUBTREE $$ 1:[email protected]#ROOT2024 1:[email protected]#ROOT2024
- PUNCH ; [alone] 0:[email protected]#ROOT2024
+ SUBTREE $$ 1:Root[0000, 0]@0..18#ROOT2024 1:Root[0000, 0]@0..18#ROOT2024
+ PUNCH ; [alone] 0:Root[0000, 0]@39..40#ROOT2024
;"#]],
);
@@ -305,26 +307,26 @@ fn expr_2021() {
break 'foo bar,
"#,
expect![[r#"
- SUBTREE $$ 1:[email protected]#ROOT2024 1:[email protected]#ROOT2024
- LITERAL Integer 4 1:[email protected]#ROOT2024
- PUNCH ; [joint] 0:[email protected]#ROOT2024
- LITERAL Str literal 1:[email protected]#ROOT2024
- PUNCH ; [joint] 0:[email protected]#ROOT2024
- SUBTREE () 0:[email protected]#ROOT2024 0:[email protected]#ROOT2024
- IDENT funcall 1:[email protected]#ROOT2024
- SUBTREE () 1:[email protected]#ROOT2024 1:[email protected]#ROOT2024
- PUNCH ; [joint] 0:[email protected]#ROOT2024
- SUBTREE () 0:[email protected]#ROOT2024 0:[email protected]#ROOT2024
- IDENT future 1:[email protected]#ROOT2024
- PUNCH . [alone] 1:[email protected]#ROOT2024
- IDENT await 1:[email protected]#ROOT2024
- PUNCH ; [joint] 0:[email protected]#ROOT2024
- SUBTREE () 0:[email protected]#ROOT2024 0:[email protected]#ROOT2024
- IDENT break 1:[email protected]#ROOT2024
- PUNCH ' [joint] 1:[email protected]#ROOT2024
- IDENT foo 1:[email protected]#ROOT2024
- IDENT bar 1:[email protected]#ROOT2024
- PUNCH ; [alone] 0:[email protected]#ROOT2024
+ SUBTREE $$ 1:Root[0000, 0]@0..76#ROOT2024 1:Root[0000, 0]@0..76#ROOT2024
+ LITERAL Integer 4 1:Root[0000, 0]@5..6#ROOT2024
+ PUNCH ; [joint] 0:Root[0000, 0]@41..42#ROOT2024
+ LITERAL Str literal 1:Root[0000, 0]@12..21#ROOT2024
+ PUNCH ; [joint] 0:Root[0000, 0]@41..42#ROOT2024
+ SUBTREE () 0:Root[0000, 0]@39..40#ROOT2024 0:Root[0000, 0]@39..40#ROOT2024
+ IDENT funcall 1:Root[0000, 0]@27..34#ROOT2024
+ SUBTREE () 1:Root[0000, 0]@34..35#ROOT2024 1:Root[0000, 0]@35..36#ROOT2024
+ PUNCH ; [joint] 0:Root[0000, 0]@41..42#ROOT2024
+ SUBTREE () 0:Root[0000, 0]@39..40#ROOT2024 0:Root[0000, 0]@39..40#ROOT2024
+ IDENT future 1:Root[0000, 0]@42..48#ROOT2024
+ PUNCH . [alone] 1:Root[0000, 0]@48..49#ROOT2024
+ IDENT await 1:Root[0000, 0]@49..54#ROOT2024
+ PUNCH ; [joint] 0:Root[0000, 0]@41..42#ROOT2024
+ SUBTREE () 0:Root[0000, 0]@39..40#ROOT2024 0:Root[0000, 0]@39..40#ROOT2024
+ IDENT break 1:Root[0000, 0]@60..65#ROOT2024
+ PUNCH ' [joint] 1:Root[0000, 0]@66..67#ROOT2024
+ IDENT foo 1:Root[0000, 0]@67..70#ROOT2024
+ IDENT bar 1:Root[0000, 0]@71..74#ROOT2024
+ PUNCH ; [alone] 0:Root[0000, 0]@44..45#ROOT2024
4;
"literal";
@@ -346,13 +348,13 @@ fn expr_2021() {
expect![[r#"
ExpandError {
inner: (
- 1:[email protected]#ROOT2024,
+ 1:Root[0000, 0]@5..6#ROOT2024,
NoMatchingRule,
),
}
- SUBTREE $$ 1:[email protected]#ROOT2024 1:[email protected]#ROOT2024
- PUNCH ; [alone] 0:[email protected]#ROOT2024
+ SUBTREE $$ 1:Root[0000, 0]@0..8#ROOT2024 1:Root[0000, 0]@0..8#ROOT2024
+ PUNCH ; [alone] 0:Root[0000, 0]@44..45#ROOT2024
;"#]],
);
@@ -370,88 +372,88 @@ fn minus_belongs_to_literal() {
check(
"-1",
expect![[r#"
- SUBTREE $$ 1:[email protected]#ROOT2024 1:[email protected]#ROOT2024
- PUNCH - [alone] 0:[email protected]#ROOT2024
- LITERAL Integer 1 0:[email protected]#ROOT2024
+ SUBTREE $$ 1:Root[0000, 0]@0..2#ROOT2024 1:Root[0000, 0]@0..2#ROOT2024
+ PUNCH - [alone] 0:Root[0000, 0]@10..11#ROOT2024
+ LITERAL Integer 1 0:Root[0000, 0]@11..12#ROOT2024
-1"#]],
);
check(
"- 1",
expect![[r#"
- SUBTREE $$ 1:[email protected]#ROOT2024 1:[email protected]#ROOT2024
- PUNCH - [alone] 0:[email protected]#ROOT2024
- LITERAL Integer 1 0:[email protected]#ROOT2024
+ SUBTREE $$ 1:Root[0000, 0]@0..3#ROOT2024 1:Root[0000, 0]@0..3#ROOT2024
+ PUNCH - [alone] 0:Root[0000, 0]@10..11#ROOT2024
+ LITERAL Integer 1 0:Root[0000, 0]@11..12#ROOT2024
-1"#]],
);
check(
"-2",
expect![[r#"
- SUBTREE $$ 1:[email protected]#ROOT2024 1:[email protected]#ROOT2024
- PUNCH - [alone] 0:[email protected]#ROOT2024
- LITERAL Integer 2 0:[email protected]#ROOT2024
+ SUBTREE $$ 1:Root[0000, 0]@0..2#ROOT2024 1:Root[0000, 0]@0..2#ROOT2024
+ PUNCH - [alone] 0:Root[0000, 0]@25..26#ROOT2024
+ LITERAL Integer 2 0:Root[0000, 0]@27..28#ROOT2024
-2"#]],
);
check(
"- 2",
expect![[r#"
- SUBTREE $$ 1:[email protected]#ROOT2024 1:[email protected]#ROOT2024
- PUNCH - [alone] 0:[email protected]#ROOT2024
- LITERAL Integer 2 0:[email protected]#ROOT2024
+ SUBTREE $$ 1:Root[0000, 0]@0..3#ROOT2024 1:Root[0000, 0]@0..3#ROOT2024
+ PUNCH - [alone] 0:Root[0000, 0]@25..26#ROOT2024
+ LITERAL Integer 2 0:Root[0000, 0]@27..28#ROOT2024
-2"#]],
);
check(
"-3.0",
expect![[r#"
- SUBTREE $$ 1:[email protected]#ROOT2024 1:[email protected]#ROOT2024
- PUNCH - [alone] 0:[email protected]#ROOT2024
- LITERAL Float 3.0 0:[email protected]#ROOT2024
+ SUBTREE $$ 1:Root[0000, 0]@0..4#ROOT2024 1:Root[0000, 0]@0..4#ROOT2024
+ PUNCH - [alone] 0:Root[0000, 0]@43..44#ROOT2024
+ LITERAL Float 3.0 0:Root[0000, 0]@45..48#ROOT2024
-3.0"#]],
);
check(
"- 3.0",
expect![[r#"
- SUBTREE $$ 1:[email protected]#ROOT2024 1:[email protected]#ROOT2024
- PUNCH - [alone] 0:[email protected]#ROOT2024
- LITERAL Float 3.0 0:[email protected]#ROOT2024
+ SUBTREE $$ 1:Root[0000, 0]@0..5#ROOT2024 1:Root[0000, 0]@0..5#ROOT2024
+ PUNCH - [alone] 0:Root[0000, 0]@43..44#ROOT2024
+ LITERAL Float 3.0 0:Root[0000, 0]@45..48#ROOT2024
-3.0"#]],
);
check(
"@1",
expect![[r#"
- SUBTREE $$ 1:[email protected]#ROOT2024 1:[email protected]#ROOT2024
- LITERAL Integer 1 1:[email protected]#ROOT2024
+ SUBTREE $$ 1:Root[0000, 0]@0..2#ROOT2024 1:Root[0000, 0]@0..2#ROOT2024
+ LITERAL Integer 1 1:Root[0000, 0]@1..2#ROOT2024
1"#]],
);
check(
"@-1",
expect![[r#"
- SUBTREE $$ 1:[email protected]#ROOT2024 1:[email protected]#ROOT2024
- PUNCH - [alone] 1:[email protected]#ROOT2024
- LITERAL Integer 1 1:[email protected]#ROOT2024
+ SUBTREE $$ 1:Root[0000, 0]@0..3#ROOT2024 1:Root[0000, 0]@0..3#ROOT2024
+ PUNCH - [alone] 1:Root[0000, 0]@1..2#ROOT2024
+ LITERAL Integer 1 1:Root[0000, 0]@2..3#ROOT2024
-1"#]],
);
check(
"@1.0",
expect![[r#"
- SUBTREE $$ 1:[email protected]#ROOT2024 1:[email protected]#ROOT2024
- LITERAL Float 1.0 1:[email protected]#ROOT2024
+ SUBTREE $$ 1:Root[0000, 0]@0..4#ROOT2024 1:Root[0000, 0]@0..4#ROOT2024
+ LITERAL Float 1.0 1:Root[0000, 0]@1..4#ROOT2024
1.0"#]],
);
check(
"@-1.0",
expect![[r#"
- SUBTREE $$ 1:[email protected]#ROOT2024 1:[email protected]#ROOT2024
- PUNCH - [alone] 1:[email protected]#ROOT2024
- LITERAL Float 1.0 1:[email protected]#ROOT2024
+ SUBTREE $$ 1:Root[0000, 0]@0..5#ROOT2024 1:Root[0000, 0]@0..5#ROOT2024
+ PUNCH - [alone] 1:Root[0000, 0]@1..2#ROOT2024
+ LITERAL Float 1.0 1:Root[0000, 0]@2..5#ROOT2024
-1.0"#]],
);
@@ -460,16 +462,16 @@ fn minus_belongs_to_literal() {
expect![[r#"
ExpandError {
inner: (
- 1:[email protected]#ROOT2024,
+ 1:Root[0000, 0]@1..2#ROOT2024,
BindingError(
"expected literal",
),
),
}
- SUBTREE $$ 1:[email protected]#ROOT2024 1:[email protected]#ROOT2024
- PUNCH - [joint] 1:[email protected]#ROOT2024
- PUNCH - [alone] 1:[email protected]#ROOT2024
+ SUBTREE $$ 1:Root[0000, 0]@0..6#ROOT2024 1:Root[0000, 0]@0..6#ROOT2024
+ PUNCH - [joint] 1:Root[0000, 0]@1..2#ROOT2024
+ PUNCH - [alone] 1:Root[0000, 0]@2..3#ROOT2024
--"#]],
);
diff --git a/crates/proc-macro-api/src/legacy_protocol/msg.rs b/crates/proc-macro-api/src/legacy_protocol/msg.rs
index 55185aa492..4e1526fe48 100644
--- a/crates/proc-macro-api/src/legacy_protocol/msg.rs
+++ b/crates/proc-macro-api/src/legacy_protocol/msg.rs
@@ -22,9 +22,10 @@ pub const HAS_GLOBAL_SPANS: u32 = 3;
pub const RUST_ANALYZER_SPAN_SUPPORT: u32 = 4;
/// Whether literals encode their kind as an additional u32 field and idents their rawness as a u32 field.
pub const EXTENDED_LEAF_DATA: u32 = 5;
+pub const HASHED_AST_ID: u32 = 6;
/// Current API version of the proc-macro protocol.
-pub const CURRENT_API_VERSION: u32 = EXTENDED_LEAF_DATA;
+pub const CURRENT_API_VERSION: u32 = HASHED_AST_ID;
/// Represents requests sent from the client to the proc-macro-srv.
#[derive(Debug, Serialize, Deserialize)]
@@ -54,7 +55,7 @@ pub enum SpanMode {
Id,
/// Rust Analyzer-specific span handling mode.
- RustAnalyzer,
+ RustAnalyzer { fixup_ast_id: u32 },
}
/// Represents responses sent from the proc-macro-srv to the client.
@@ -201,7 +202,9 @@ type ProtocolWrite<W: Write> = for<'o, 'msg> fn(out: &'o mut W, msg: &'msg str)
#[cfg(test)]
mod tests {
use intern::{Symbol, sym};
- use span::{Edition, ErasedFileAstId, Span, SpanAnchor, SyntaxContext, TextRange, TextSize};
+ use span::{
+ Edition, ROOT_ERASED_FILE_AST_ID, Span, SpanAnchor, SyntaxContext, TextRange, TextSize,
+ };
use tt::{
Delimiter, DelimiterKind, Ident, Leaf, Literal, Punct, Spacing, TopSubtree,
TopSubtreeBuilder,
@@ -215,7 +218,7 @@ mod tests {
span::FileId::from_raw(0xe4e4e),
span::Edition::CURRENT,
),
- ast_id: ErasedFileAstId::from_raw(0),
+ ast_id: ROOT_ERASED_FILE_AST_ID,
};
let mut builder = TopSubtreeBuilder::new(Delimiter {
@@ -305,7 +308,7 @@ mod tests {
#[test]
fn test_proc_macro_rpc_works() {
let tt = fixture_token_tree();
- for v in RUST_ANALYZER_SPAN_SUPPORT..=CURRENT_API_VERSION {
+ for v in HASHED_AST_ID..=CURRENT_API_VERSION {
let mut span_data_table = Default::default();
let task = ExpandMacro {
data: ExpandMacroData {
diff --git a/crates/proc-macro-api/src/process.rs b/crates/proc-macro-api/src/process.rs
index fcea75ef67..e3b0614546 100644
--- a/crates/proc-macro-api/src/process.rs
+++ b/crates/proc-macro-api/src/process.rs
@@ -8,6 +8,7 @@ use std::{
};
use paths::AbsPath;
+use span::FIXUP_ERASED_FILE_AST_ID_MARKER;
use stdx::JodChild;
use crate::{
@@ -15,8 +16,7 @@ use crate::{
legacy_protocol::{
json::{read_json, write_json},
msg::{
- CURRENT_API_VERSION, Message, RUST_ANALYZER_SPAN_SUPPORT, Request, Response,
- ServerConfig, SpanMode,
+ CURRENT_API_VERSION, HASHED_AST_ID, Message, Request, Response, ServerConfig, SpanMode,
},
},
};
@@ -71,7 +71,9 @@ impl ProcMacroServerProcess {
Ok(v) => {
tracing::info!("Proc-macro server version: {v}");
srv.version = v;
- if srv.version >= RUST_ANALYZER_SPAN_SUPPORT {
+ if srv.version >= HASHED_AST_ID {
+ // We don't enable spans on versions prior to `HASHED_AST_ID`, because their ast id layout
+ // is different.
if let Ok(mode) = srv.enable_rust_analyzer_spans() {
srv.mode = mode;
}
@@ -111,7 +113,11 @@ impl ProcMacroServerProcess {
/// Enable support for rust-analyzer span mode if the server supports it.
fn enable_rust_analyzer_spans(&self) -> Result<SpanMode, ServerError> {
- let request = Request::SetConfig(ServerConfig { span_mode: SpanMode::RustAnalyzer });
+ let request = Request::SetConfig(ServerConfig {
+ span_mode: SpanMode::RustAnalyzer {
+ fixup_ast_id: FIXUP_ERASED_FILE_AST_ID_MARKER.into_raw(),
+ },
+ });
let response = self.send_task(request)?;
match response {
diff --git a/crates/proc-macro-srv-cli/src/main_loop.rs b/crates/proc-macro-srv-cli/src/main_loop.rs
index f54dff1f2d..25a49fbff9 100644
--- a/crates/proc-macro-srv-cli/src/main_loop.rs
+++ b/crates/proc-macro-srv-cli/src/main_loop.rs
@@ -26,7 +26,7 @@ pub(crate) fn run() -> io::Result<()> {
let write_response = |msg: msg::Response| msg.write(write_json, &mut io::stdout().lock());
let env = EnvSnapshot::default();
- let srv = proc_macro_srv::ProcMacroSrv::new(&env);
+ let mut srv = proc_macro_srv::ProcMacroSrv::new(&env);
let mut span_mode = SpanMode::Id;
@@ -78,7 +78,7 @@ pub(crate) fn run() -> io::Result<()> {
})
.map_err(msg::PanicMessage)
}),
- SpanMode::RustAnalyzer => msg::Response::ExpandMacroExtended({
+ SpanMode::RustAnalyzer { .. } => msg::Response::ExpandMacroExtended({
let mut span_data_table = deserialize_span_data_index_map(&span_data_table);
let def_site = span_data_table[def_site];
@@ -122,6 +122,9 @@ pub(crate) fn run() -> io::Result<()> {
msg::Request::ApiVersionCheck {} => msg::Response::ApiVersionCheck(CURRENT_API_VERSION),
msg::Request::SetConfig(config) => {
span_mode = config.span_mode;
+ if let SpanMode::RustAnalyzer { fixup_ast_id } = span_mode {
+ srv.set_fixup_ast_id(fixup_ast_id);
+ }
msg::Response::SetConfig(config)
}
};
diff --git a/crates/proc-macro-srv/src/dylib.rs b/crates/proc-macro-srv/src/dylib.rs
index c49159df99..c64a9833e3 100644
--- a/crates/proc-macro-srv/src/dylib.rs
+++ b/crates/proc-macro-srv/src/dylib.rs
@@ -3,6 +3,7 @@
mod version;
use proc_macro::bridge;
+use span::ErasedFileAstId;
use std::{fmt, fs, io, time::SystemTime};
use libloading::Library;
@@ -161,14 +162,20 @@ impl Expander {
def_site: S,
call_site: S,
mixed_site: S,
+ fixup_ast_id: ErasedFileAstId,
) -> Result<TopSubtree<S>, String>
where
<S::Server as bridge::server::Types>::TokenStream: Default,
{
- let result = self
- .inner
- .proc_macros
- .expand(macro_name, macro_body, attributes, def_site, call_site, mixed_site);
+ let result = self.inner.proc_macros.expand(
+ macro_name,
+ macro_body,
+ attributes,
+ def_site,
+ call_site,
+ mixed_site,
+ fixup_ast_id,
+ );
result.map_err(|e| e.into_string().unwrap_or_default())
}
diff --git a/crates/proc-macro-srv/src/lib.rs b/crates/proc-macro-srv/src/lib.rs
index 223c5a54b7..22afa018de 100644
--- a/crates/proc-macro-srv/src/lib.rs
+++ b/crates/proc-macro-srv/src/lib.rs
@@ -41,7 +41,7 @@ use std::{
};
use paths::{Utf8Path, Utf8PathBuf};
-use span::{Span, TokenId};
+use span::{ErasedFileAstId, FIXUP_ERASED_FILE_AST_ID_MARKER, Span, TokenId};
use crate::server_impl::TokenStream;
@@ -57,11 +57,16 @@ pub const RUSTC_VERSION_STRING: &str = env!("RUSTC_VERSION");
pub struct ProcMacroSrv<'env> {
expanders: Mutex<HashMap<Utf8PathBuf, Arc<dylib::Expander>>>,
env: &'env EnvSnapshot,
+ fixup_ast_id: ErasedFileAstId,
}
impl<'env> ProcMacroSrv<'env> {
pub fn new(env: &'env EnvSnapshot) -> Self {
- Self { expanders: Default::default(), env }
+ Self { expanders: Default::default(), env, fixup_ast_id: FIXUP_ERASED_FILE_AST_ID_MARKER }
+ }
+
+ pub fn set_fixup_ast_id(&mut self, fixup_ast_id: u32) {
+ self.fixup_ast_id = ErasedFileAstId::from_raw(fixup_ast_id);
}
}
@@ -101,6 +106,7 @@ impl ProcMacroSrv<'_> {
def_site,
call_site,
mixed_site,
+ self.fixup_ast_id,
)
.map(|tt| tt.0)
});
@@ -156,25 +162,41 @@ impl ProcMacroSrv<'_> {
pub trait ProcMacroSrvSpan: Copy + Send {
type Server: proc_macro::bridge::server::Server<TokenStream = TokenStream<Self>>;
- fn make_server(call_site: Self, def_site: Self, mixed_site: Self) -> Self::Server;
+ fn make_server(
+ call_site: Self,
+ def_site: Self,
+ mixed_site: Self,
+ fixup_ast_id: ErasedFileAstId,
+ ) -> Self::Server;
}
impl ProcMacroSrvSpan for TokenId {
type Server = server_impl::token_id::TokenIdServer;
- fn make_server(call_site: Self, def_site: Self, mixed_site: Self) -> Self::Server {
+ fn make_server(
+ call_site: Self,
+ def_site: Self,
+ mixed_site: Self,
+ _fixup_ast_id: ErasedFileAstId,
+ ) -> Self::Server {
Self::Server { call_site, def_site, mixed_site }
}
}
impl ProcMacroSrvSpan for Span {
type Server = server_impl::rust_analyzer_span::RaSpanServer;
- fn make_server(call_site: Self, def_site: Self, mixed_site: Self) -> Self::Server {
+ fn make_server(
+ call_site: Self,
+ def_site: Self,
+ mixed_site: Self,
+ fixup_ast_id: ErasedFileAstId,
+ ) -> Self::Server {
Self::Server {
call_site,
def_site,
mixed_site,
tracked_env_vars: Default::default(),
tracked_paths: Default::default(),
+ fixup_ast_id,
}
}
}
diff --git a/crates/proc-macro-srv/src/proc_macros.rs b/crates/proc-macro-srv/src/proc_macros.rs
index 18532706c4..3b9c45894c 100644
--- a/crates/proc-macro-srv/src/proc_macros.rs
+++ b/crates/proc-macro-srv/src/proc_macros.rs
@@ -1,6 +1,7 @@
//! Proc macro ABI
use proc_macro::bridge;
+use span::ErasedFileAstId;
use crate::{ProcMacroKind, ProcMacroSrvSpan, server_impl::TopSubtree};
@@ -22,6 +23,7 @@ impl ProcMacros {
def_site: S,
call_site: S,
mixed_site: S,
+ fixup_ast_id: ErasedFileAstId,
) -> Result<TopSubtree<S>, crate::PanicMessage> {
let parsed_body = crate::server_impl::TokenStream::with_subtree(macro_body);
@@ -37,7 +39,7 @@ impl ProcMacros {
{
let res = client.run(
&bridge::server::SameThread,
- S::make_server(call_site, def_site, mixed_site),
+ S::make_server(call_site, def_site, mixed_site, fixup_ast_id),
parsed_body,
cfg!(debug_assertions),
);
@@ -48,7 +50,7 @@ impl ProcMacros {
bridge::client::ProcMacro::Bang { name, client } if *name == macro_name => {
let res = client.run(
&bridge::server::SameThread,
- S::make_server(call_site, def_site, mixed_site),
+ S::make_server(call_site, def_site, mixed_site, fixup_ast_id),
parsed_body,
cfg!(debug_assertions),
);
@@ -59,7 +61,7 @@ impl ProcMacros {
bridge::client::ProcMacro::Attr { name, client } if *name == macro_name => {
let res = client.run(
&bridge::server::SameThread,
- S::make_server(call_site, def_site, mixed_site),
+ S::make_server(call_site, def_site, mixed_site, fixup_ast_id),
parsed_attributes,
parsed_body,
cfg!(debug_assertions),
diff --git a/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs b/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs
index 5d1271ba81..b071ad80f5 100644
--- a/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs
+++ b/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs
@@ -11,7 +11,7 @@ use std::{
use intern::Symbol;
use proc_macro::bridge::{self, server};
-use span::{FIXUP_ERASED_FILE_AST_ID_MARKER, Span};
+use span::{ErasedFileAstId, Span};
use tt::{TextRange, TextSize};
use crate::server_impl::{from_token_tree, literal_from_str, token_stream::TokenStreamBuilder};
@@ -28,6 +28,7 @@ pub struct RaSpanServer {
pub call_site: Span,
pub def_site: Span,
pub mixed_site: Span,
+ pub fixup_ast_id: ErasedFileAstId,
}
impl server::Types for RaSpanServer {
@@ -181,10 +182,10 @@ impl server::Span for RaSpanServer {
fn join(&mut self, first: Self::Span, second: Self::Span) -> Option<Self::Span> {
// We can't modify the span range for fixup spans, those are meaningful to fixup, so just
// prefer the non-fixup span.
- if first.anchor.ast_id == FIXUP_ERASED_FILE_AST_ID_MARKER {
+ if first.anchor.ast_id == self.fixup_ast_id {
return Some(second);
}
- if second.anchor.ast_id == FIXUP_ERASED_FILE_AST_ID_MARKER {
+ if second.anchor.ast_id == self.fixup_ast_id {
return Some(first);
}
// FIXME: Once we can talk back to the client, implement a "long join" request for anchors
@@ -213,7 +214,7 @@ impl server::Span for RaSpanServer {
end: Bound<usize>,
) -> Option<Self::Span> {
// We can't modify the span range for fixup spans, those are meaningful to fixup.
- if span.anchor.ast_id == FIXUP_ERASED_FILE_AST_ID_MARKER {
+ if span.anchor.ast_id == self.fixup_ast_id {
return Some(span);
}
let length = span.range.len().into();
@@ -256,7 +257,7 @@ impl server::Span for RaSpanServer {
fn end(&mut self, span: Self::Span) -> Self::Span {
// We can't modify the span range for fixup spans, those are meaningful to fixup.
- if span.anchor.ast_id == FIXUP_ERASED_FILE_AST_ID_MARKER {
+ if span.anchor.ast_id == self.fixup_ast_id {
return span;
}
Span { range: TextRange::empty(span.range.end()), ..span }
@@ -264,7 +265,7 @@ impl server::Span for RaSpanServer {
fn start(&mut self, span: Self::Span) -> Self::Span {
// We can't modify the span range for fixup spans, those are meaningful to fixup.
- if span.anchor.ast_id == FIXUP_ERASED_FILE_AST_ID_MARKER {
+ if span.anchor.ast_id == self.fixup_ast_id {
return span;
}
Span { range: TextRange::empty(span.range.start()), ..span }
@@ -318,7 +319,7 @@ mod tests {
range: TextRange::empty(TextSize::new(0)),
anchor: span::SpanAnchor {
file_id: EditionedFileId::current_edition(FileId::from_raw(0)),
- ast_id: span::ErasedFileAstId::from_raw(0),
+ ast_id: span::ROOT_ERASED_FILE_AST_ID,
},
ctx: SyntaxContext::root(span::Edition::CURRENT),
};
@@ -360,7 +361,7 @@ mod tests {
range: TextRange::empty(TextSize::new(0)),
anchor: span::SpanAnchor {
file_id: EditionedFileId::current_edition(FileId::from_raw(0)),
- ast_id: span::ErasedFileAstId::from_raw(0),
+ ast_id: span::ROOT_ERASED_FILE_AST_ID,
},
ctx: SyntaxContext::root(span::Edition::CURRENT),
};
diff --git a/crates/proc-macro-srv/src/tests/mod.rs b/crates/proc-macro-srv/src/tests/mod.rs
index d1ea89d2dc..08495f50bf 100644
--- a/crates/proc-macro-srv/src/tests/mod.rs
+++ b/crates/proc-macro-srv/src/tests/mod.rs
@@ -21,14 +21,14 @@ fn test_derive_empty() {
SUBTREE $$ 1 1"#]],
expect![[r#"
- SUBTREE $$ 42:[email protected]#ROOT2024 42:[email protected]#ROOT2024
- IDENT struct 42:[email protected]#ROOT2024
- IDENT S 42:[email protected]#ROOT2024
- PUNCH ; [alone] 42:[email protected]#ROOT2024
+ SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024
+ IDENT struct 42:Root[0000, 0]@0..6#ROOT2024
+ IDENT S 42:Root[0000, 0]@7..8#ROOT2024
+ PUNCH ; [alone] 42:Root[0000, 0]@8..9#ROOT2024
- SUBTREE $$ 42:[email protected]#ROOT2024 42:[email protected]#ROOT2024"#]],
+ SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024"#]],
);
}
@@ -52,19 +52,19 @@ fn test_derive_error() {
LITERAL Str #[derive(DeriveError)] struct S ; 1
PUNCH ; [alone] 1"#]],
expect![[r#"
- SUBTREE $$ 42:[email protected]#ROOT2024 42:[email protected]#ROOT2024
- IDENT struct 42:[email protected]#ROOT2024
- IDENT S 42:[email protected]#ROOT2024
- PUNCH ; [alone] 42:[email protected]#ROOT2024
+ SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024
+ IDENT struct 42:Root[0000, 0]@0..6#ROOT2024
+ IDENT S 42:Root[0000, 0]@7..8#ROOT2024
+ PUNCH ; [alone] 42:Root[0000, 0]@8..9#ROOT2024
- SUBTREE $$ 42:[email protected]#ROOT2024 42:[email protected]#ROOT2024
- IDENT compile_error 42:[email protected]#ROOT2024
- PUNCH ! [alone] 42:[email protected]#ROOT2024
- SUBTREE () 42:[email protected]#ROOT2024 42:[email protected]#ROOT2024
- LITERAL Str #[derive(DeriveError)] struct S ; 42:[email protected]#ROOT2024
- PUNCH ; [alone] 42:[email protected]#ROOT2024"#]],
+ SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024
+ IDENT compile_error 42:Root[0000, 0]@0..100#ROOT2024
+ PUNCH ! [alone] 42:Root[0000, 0]@0..100#ROOT2024
+ SUBTREE () 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024
+ LITERAL Str #[derive(DeriveError)] struct S ; 42:Root[0000, 0]@0..100#ROOT2024
+ PUNCH ; [alone] 42:Root[0000, 0]@0..100#ROOT2024"#]],
);
}
@@ -94,25 +94,25 @@ fn test_fn_like_macro_noop() {
PUNCH , [alone] 1
SUBTREE [] 1 1"#]],
expect![[r#"
- SUBTREE $$ 42:[email protected]#ROOT2024 42:[email protected]#ROOT2024
- IDENT ident 42:[email protected]#ROOT2024
- PUNCH , [alone] 42:[email protected]#ROOT2024
- LITERAL Integer 0 42:[email protected]#ROOT2024
- PUNCH , [alone] 42:[email protected]#ROOT2024
- LITERAL Integer 1 42:[email protected]#ROOT2024
- PUNCH , [alone] 42:[email protected]#ROOT2024
- SUBTREE [] 42:[email protected]#ROOT2024 42:[email protected]#ROOT2024
-
-
-
- SUBTREE $$ 42:[email protected]#ROOT2024 42:[email protected]#ROOT2024
- IDENT ident 42:[email protected]#ROOT2024
- PUNCH , [alone] 42:[email protected]#ROOT2024
- LITERAL Integer 0 42:[email protected]#ROOT2024
- PUNCH , [alone] 42:[email protected]#ROOT2024
- LITERAL Integer 1 42:[email protected]#ROOT2024
- PUNCH , [alone] 42:[email protected]#ROOT2024
- SUBTREE [] 42:[email protected]#ROOT2024 42:[email protected]#ROOT2024"#]],
+ SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024
+ IDENT ident 42:Root[0000, 0]@0..5#ROOT2024
+ PUNCH , [alone] 42:Root[0000, 0]@5..6#ROOT2024
+ LITERAL Integer 0 42:Root[0000, 0]@7..8#ROOT2024
+ PUNCH , [alone] 42:Root[0000, 0]@8..9#ROOT2024
+ LITERAL Integer 1 42:Root[0000, 0]@10..11#ROOT2024
+ PUNCH , [alone] 42:Root[0000, 0]@11..12#ROOT2024
+ SUBTREE [] 42:Root[0000, 0]@13..14#ROOT2024 42:Root[0000, 0]@14..15#ROOT2024
+
+
+
+ SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024
+ IDENT ident 42:Root[0000, 0]@0..5#ROOT2024
+ PUNCH , [alone] 42:Root[0000, 0]@5..6#ROOT2024
+ LITERAL Integer 0 42:Root[0000, 0]@7..8#ROOT2024
+ PUNCH , [alone] 42:Root[0000, 0]@8..9#ROOT2024
+ LITERAL Integer 1 42:Root[0000, 0]@10..11#ROOT2024
+ PUNCH , [alone] 42:Root[0000, 0]@11..12#ROOT2024
+ SUBTREE [] 42:Root[0000, 0]@13..14#ROOT2024 42:Root[0000, 0]@14..15#ROOT2024"#]],
);
}
@@ -134,17 +134,17 @@ fn test_fn_like_macro_clone_ident_subtree() {
PUNCH , [alone] 1
SUBTREE [] 1 1"#]],
expect![[r#"
- SUBTREE $$ 42:[email protected]#ROOT2024 42:[email protected]#ROOT2024
- IDENT ident 42:[email protected]#ROOT2024
- PUNCH , [alone] 42:[email protected]#ROOT2024
- SUBTREE [] 42:[email protected]#ROOT2024 42:[email protected]#ROOT2024
+ SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024
+ IDENT ident 42:Root[0000, 0]@0..5#ROOT2024
+ PUNCH , [alone] 42:Root[0000, 0]@5..6#ROOT2024
+ SUBTREE [] 42:Root[0000, 0]@7..8#ROOT2024 42:Root[0000, 0]@8..9#ROOT2024
- SUBTREE $$ 42:[email protected]#ROOT2024 42:[email protected]#ROOT2024
- IDENT ident 42:[email protected]#ROOT2024
- PUNCH , [alone] 42:[email protected]#ROOT2024
- SUBTREE [] 42:[email protected]#ROOT2024 42:[email protected]#ROOT2024"#]],
+ SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024
+ IDENT ident 42:Root[0000, 0]@0..5#ROOT2024
+ PUNCH , [alone] 42:Root[0000, 0]@5..6#ROOT2024
+ SUBTREE [] 42:Root[0000, 0]@7..9#ROOT2024 42:Root[0000, 0]@7..9#ROOT2024"#]],
);
}
@@ -162,13 +162,13 @@ fn test_fn_like_macro_clone_raw_ident() {
SUBTREE $$ 1 1
IDENT r#async 1"#]],
expect![[r#"
- SUBTREE $$ 42:[email protected]#ROOT2024 42:[email protected]#ROOT2024
- IDENT r#async 42:[email protected]#ROOT2024
+ SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024
+ IDENT r#async 42:Root[0000, 0]@0..7#ROOT2024
- SUBTREE $$ 42:[email protected]#ROOT2024 42:[email protected]#ROOT2024
- IDENT r#async 42:[email protected]#ROOT2024"#]],
+ SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024
+ IDENT r#async 42:Root[0000, 0]@0..7#ROOT2024"#]],
);
}
@@ -187,14 +187,14 @@ fn test_fn_like_fn_like_span_join() {
SUBTREE $$ 1 1
IDENT r#joined 1"#]],
expect![[r#"
- SUBTREE $$ 42:[email protected]#ROOT2024 42:[email protected]#ROOT2024
- IDENT foo 42:[email protected]#ROOT2024
- IDENT bar 42:[email protected]#ROOT2024
+ SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024
+ IDENT foo 42:Root[0000, 0]@0..3#ROOT2024
+ IDENT bar 42:Root[0000, 0]@8..11#ROOT2024
- SUBTREE $$ 42:[email protected]#ROOT2024 42:[email protected]#ROOT2024
- IDENT r#joined 42:[email protected]#ROOT2024"#]],
+ SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024
+ IDENT r#joined 42:Root[0000, 0]@0..11#ROOT2024"#]],
);
}
@@ -216,17 +216,17 @@ fn test_fn_like_fn_like_span_ops() {
IDENT resolved_at_def_site 1
IDENT start_span 1"#]],
expect![[r#"
- SUBTREE $$ 42:[email protected]#ROOT2024 42:[email protected]#ROOT2024
- IDENT set_def_site 42:[email protected]#ROOT2024
- IDENT resolved_at_def_site 42:[email protected]#ROOT2024
- IDENT start_span 42:[email protected]#ROOT2024
+ SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024
+ IDENT set_def_site 42:Root[0000, 0]@0..12#ROOT2024
+ IDENT resolved_at_def_site 42:Root[0000, 0]@13..33#ROOT2024
+ IDENT start_span 42:Root[0000, 0]@34..44#ROOT2024
- SUBTREE $$ 42:[email protected]#ROOT2024 42:[email protected]#ROOT2024
- IDENT set_def_site 41:[email protected]#ROOT2024
- IDENT resolved_at_def_site 42:[email protected]#ROOT2024
- IDENT start_span 42:[email protected]#ROOT2024"#]],
+ SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024
+ IDENT set_def_site 41:Root[0000, 0]@0..150#ROOT2024
+ IDENT resolved_at_def_site 42:Root[0000, 0]@13..33#ROOT2024
+ IDENT start_span 42:Root[0000, 0]@34..34#ROOT2024"#]],
);
}
@@ -259,28 +259,28 @@ fn test_fn_like_mk_literals() {
PUNCH - [alone] 1
LITERAL Integer 123 1"#]],
expect![[r#"
- SUBTREE $$ 42:[email protected]#ROOT2024 42:[email protected]#ROOT2024
-
-
-
- SUBTREE $$ 42:[email protected]#ROOT2024 42:[email protected]#ROOT2024
- LITERAL ByteStr byte_string 42:[email protected]#ROOT2024
- LITERAL Char c 42:[email protected]#ROOT2024
- LITERAL Str string 42:[email protected]#ROOT2024
- LITERAL Str -string 42:[email protected]#ROOT2024
- LITERAL CStr cstring 42:[email protected]#ROOT2024
- LITERAL Float 3.14f64 42:[email protected]#ROOT2024
- PUNCH - [alone] 42:[email protected]#ROOT2024
- LITERAL Float 3.14f64 42:[email protected]#ROOT2024
- LITERAL Float 3.14 42:[email protected]#ROOT2024
- PUNCH - [alone] 42:[email protected]#ROOT2024
- LITERAL Float 3.14 42:[email protected]#ROOT2024
- LITERAL Integer 123i64 42:[email protected]#ROOT2024
- PUNCH - [alone] 42:[email protected]#ROOT2024
- LITERAL Integer 123i64 42:[email protected]#ROOT2024
- LITERAL Integer 123 42:[email protected]#ROOT2024
- PUNCH - [alone] 42:[email protected]#ROOT2024
- LITERAL Integer 123 42:[email protected]#ROOT2024"#]],
+ SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024
+
+
+
+ SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024
+ LITERAL ByteStr byte_string 42:Root[0000, 0]@0..100#ROOT2024
+ LITERAL Char c 42:Root[0000, 0]@0..100#ROOT2024
+ LITERAL Str string 42:Root[0000, 0]@0..100#ROOT2024
+ LITERAL Str -string 42:Root[0000, 0]@0..100#ROOT2024
+ LITERAL CStr cstring 42:Root[0000, 0]@0..100#ROOT2024
+ LITERAL Float 3.14f64 42:Root[0000, 0]@0..100#ROOT2024
+ PUNCH - [alone] 42:Root[0000, 0]@0..100#ROOT2024
+ LITERAL Float 3.14f64 42:Root[0000, 0]@0..100#ROOT2024
+ LITERAL Float 3.14 42:Root[0000, 0]@0..100#ROOT2024
+ PUNCH - [alone] 42:Root[0000, 0]@0..100#ROOT2024
+ LITERAL Float 3.14 42:Root[0000, 0]@0..100#ROOT2024
+ LITERAL Integer 123i64 42:Root[0000, 0]@0..100#ROOT2024
+ PUNCH - [alone] 42:Root[0000, 0]@0..100#ROOT2024
+ LITERAL Integer 123i64 42:Root[0000, 0]@0..100#ROOT2024
+ LITERAL Integer 123 42:Root[0000, 0]@0..100#ROOT2024
+ PUNCH - [alone] 42:Root[0000, 0]@0..100#ROOT2024
+ LITERAL Integer 123 42:Root[0000, 0]@0..100#ROOT2024"#]],
);
}
@@ -298,13 +298,13 @@ fn test_fn_like_mk_idents() {
IDENT standard 1
IDENT r#raw 1"#]],
expect![[r#"
- SUBTREE $$ 42:[email protected]#ROOT2024 42:[email protected]#ROOT2024
+ SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024
- SUBTREE $$ 42:[email protected]#ROOT2024 42:[email protected]#ROOT2024
- IDENT standard 42:[email protected]#ROOT2024
- IDENT r#raw 42:[email protected]#ROOT2024"#]],
+ SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024
+ IDENT standard 42:Root[0000, 0]@0..100#ROOT2024
+ IDENT r#raw 42:Root[0000, 0]@0..100#ROOT2024"#]],
);
}
@@ -360,51 +360,51 @@ fn test_fn_like_macro_clone_literals() {
PUNCH , [alone] 1
LITERAL CStr null 1"#]],
expect![[r#"
- SUBTREE $$ 42:[email protected]#ROOT2024 42:[email protected]#ROOT2024
- LITERAL Integer 1u16 42:[email protected]#ROOT2024
- PUNCH , [alone] 42:[email protected]#ROOT2024
- LITERAL Integer 2_u32 42:[email protected]#ROOT2024
- PUNCH , [alone] 42:[email protected]#ROOT2024
- PUNCH - [alone] 42:[email protected]#ROOT2024
- LITERAL Integer 4i64 42:[email protected]#ROOT2024
- PUNCH , [alone] 42:[email protected]#ROOT2024
- LITERAL Float 3.14f32 42:[email protected]#ROOT2024
- PUNCH , [alone] 42:[email protected]#ROOT2024
- LITERAL Str hello bridge 42:[email protected]#ROOT2024
- PUNCH , [alone] 42:[email protected]#ROOT2024
- LITERAL Str suffixedsuffix 42:[email protected]#ROOT2024
- PUNCH , [alone] 42:[email protected]#ROOT2024
- LITERAL StrRaw(2) raw 42:[email protected]#ROOT2024
- PUNCH , [alone] 42:[email protected]#ROOT2024
- LITERAL Char a 42:[email protected]#ROOT2024
- PUNCH , [alone] 42:[email protected]#ROOT2024
- LITERAL Byte b 42:[email protected]#ROOT2024
- PUNCH , [alone] 42:[email protected]#ROOT2024
- LITERAL CStr null 42:[email protected]#ROOT2024
-
-
-
- SUBTREE $$ 42:[email protected]#ROOT2024 42:[email protected]#ROOT2024
- LITERAL Integer 1u16 42:[email protected]#ROOT2024
- PUNCH , [alone] 42:[email protected]#ROOT2024
- LITERAL Integer 2_u32 42:[email protected]#ROOT2024
- PUNCH , [alone] 42:[email protected]#ROOT2024
- PUNCH - [alone] 42:[email protected]#ROOT2024
- LITERAL Integer 4i64 42:[email protected]#ROOT2024
- PUNCH , [alone] 42:[email protected]#ROOT2024
- LITERAL Float 3.14f32 42:[email protected]#ROOT2024
- PUNCH , [alone] 42:[email protected]#ROOT2024
- LITERAL Str hello bridge 42:[email protected]#ROOT2024
- PUNCH , [alone] 42:[email protected]#ROOT2024
- LITERAL Str suffixedsuffix 42:[email protected]#ROOT2024
- PUNCH , [alone] 42:[email protected]#ROOT2024
- LITERAL StrRaw(2) raw 42:[email protected]#ROOT2024
- PUNCH , [alone] 42:[email protected]#ROOT2024
- LITERAL Char a 42:[email protected]#ROOT2024
- PUNCH , [alone] 42:[email protected]#ROOT2024
- LITERAL Byte b 42:[email protected]#ROOT2024
- PUNCH , [alone] 42:[email protected]#ROOT2024
- LITERAL CStr null 42:[email protected]#ROOT2024"#]],
+ SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024
+ LITERAL Integer 1u16 42:Root[0000, 0]@0..4#ROOT2024
+ PUNCH , [alone] 42:Root[0000, 0]@4..5#ROOT2024
+ LITERAL Integer 2_u32 42:Root[0000, 0]@6..11#ROOT2024
+ PUNCH , [alone] 42:Root[0000, 0]@11..12#ROOT2024
+ PUNCH - [alone] 42:Root[0000, 0]@13..14#ROOT2024
+ LITERAL Integer 4i64 42:Root[0000, 0]@14..18#ROOT2024
+ PUNCH , [alone] 42:Root[0000, 0]@18..19#ROOT2024
+ LITERAL Float 3.14f32 42:Root[0000, 0]@20..27#ROOT2024
+ PUNCH , [alone] 42:Root[0000, 0]@27..28#ROOT2024
+ LITERAL Str hello bridge 42:Root[0000, 0]@29..43#ROOT2024
+ PUNCH , [alone] 42:Root[0000, 0]@43..44#ROOT2024
+ LITERAL Str suffixedsuffix 42:Root[0000, 0]@45..61#ROOT2024
+ PUNCH , [alone] 42:Root[0000, 0]@61..62#ROOT2024
+ LITERAL StrRaw(2) raw 42:Root[0000, 0]@63..73#ROOT2024
+ PUNCH , [alone] 42:Root[0000, 0]@73..74#ROOT2024
+ LITERAL Char a 42:Root[0000, 0]@75..78#ROOT2024
+ PUNCH , [alone] 42:Root[0000, 0]@78..79#ROOT2024
+ LITERAL Byte b 42:Root[0000, 0]@80..84#ROOT2024
+ PUNCH , [alone] 42:Root[0000, 0]@84..85#ROOT2024
+ LITERAL CStr null 42:Root[0000, 0]@86..93#ROOT2024
+
+
+
+ SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024
+ LITERAL Integer 1u16 42:Root[0000, 0]@0..4#ROOT2024
+ PUNCH , [alone] 42:Root[0000, 0]@4..5#ROOT2024
+ LITERAL Integer 2_u32 42:Root[0000, 0]@6..11#ROOT2024
+ PUNCH , [alone] 42:Root[0000, 0]@11..12#ROOT2024
+ PUNCH - [alone] 42:Root[0000, 0]@13..14#ROOT2024
+ LITERAL Integer 4i64 42:Root[0000, 0]@14..18#ROOT2024
+ PUNCH , [alone] 42:Root[0000, 0]@18..19#ROOT2024
+ LITERAL Float 3.14f32 42:Root[0000, 0]@20..27#ROOT2024
+ PUNCH , [alone] 42:Root[0000, 0]@27..28#ROOT2024
+ LITERAL Str hello bridge 42:Root[0000, 0]@29..43#ROOT2024
+ PUNCH , [alone] 42:Root[0000, 0]@43..44#ROOT2024
+ LITERAL Str suffixedsuffix 42:Root[0000, 0]@45..61#ROOT2024
+ PUNCH , [alone] 42:Root[0000, 0]@61..62#ROOT2024
+ LITERAL StrRaw(2) raw 42:Root[0000, 0]@63..73#ROOT2024
+ PUNCH , [alone] 42:Root[0000, 0]@73..74#ROOT2024
+ LITERAL Char a 42:Root[0000, 0]@75..78#ROOT2024
+ PUNCH , [alone] 42:Root[0000, 0]@78..79#ROOT2024
+ LITERAL Byte b 42:Root[0000, 0]@80..84#ROOT2024
+ PUNCH , [alone] 42:Root[0000, 0]@84..85#ROOT2024
+ LITERAL CStr null 42:Root[0000, 0]@86..93#ROOT2024"#]],
);
}
@@ -442,33 +442,33 @@ fn test_fn_like_macro_negative_literals() {
PUNCH - [alone] 1
LITERAL Float 2.7 1"#]],
expect![[r#"
- SUBTREE $$ 42:[email protected]#ROOT2024 42:[email protected]#ROOT2024
- PUNCH - [alone] 42:[email protected]#ROOT2024
- LITERAL Integer 1u16 42:[email protected]#ROOT2024
- PUNCH , [alone] 42:[email protected]#ROOT2024
- PUNCH - [alone] 42:[email protected]#ROOT2024
- LITERAL Integer 2_u32 42:[email protected]#ROOT2024
- PUNCH , [alone] 42:[email protected]#ROOT2024
- PUNCH - [alone] 42:[email protected]#ROOT2024
- LITERAL Float 3.14f32 42:[email protected]#ROOT2024
- PUNCH , [alone] 42:[email protected]#ROOT2024
- PUNCH - [alone] 42:[email protected]#ROOT2024
- LITERAL Float 2.7 42:[email protected]#ROOT2024
-
-
-
- SUBTREE $$ 42:[email protected]#ROOT2024 42:[email protected]#ROOT2024
- PUNCH - [alone] 42:[email protected]#ROOT2024
- LITERAL Integer 1u16 42:[email protected]#ROOT2024
- PUNCH , [alone] 42:[email protected]#ROOT2024
- PUNCH - [alone] 42:[email protected]#ROOT2024
- LITERAL Integer 2_u32 42:[email protected]#ROOT2024
- PUNCH , [alone] 42:[email protected]#ROOT2024
- PUNCH - [alone] 42:[email protected]#ROOT2024
- LITERAL Float 3.14f32 42:[email protected]#ROOT2024
- PUNCH , [alone] 42:[email protected]#ROOT2024
- PUNCH - [alone] 42:[email protected]#ROOT2024
- LITERAL Float 2.7 42:[email protected]#ROOT2024"#]],
+ SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024
+ PUNCH - [alone] 42:Root[0000, 0]@0..1#ROOT2024
+ LITERAL Integer 1u16 42:Root[0000, 0]@1..5#ROOT2024
+ PUNCH , [alone] 42:Root[0000, 0]@5..6#ROOT2024
+ PUNCH - [alone] 42:Root[0000, 0]@7..8#ROOT2024
+ LITERAL Integer 2_u32 42:Root[0000, 0]@9..14#ROOT2024
+ PUNCH , [alone] 42:Root[0000, 0]@14..15#ROOT2024
+ PUNCH - [alone] 42:Root[0000, 0]@16..17#ROOT2024
+ LITERAL Float 3.14f32 42:Root[0000, 0]@17..24#ROOT2024
+ PUNCH , [alone] 42:Root[0000, 0]@24..25#ROOT2024
+ PUNCH - [alone] 42:Root[0000, 0]@26..27#ROOT2024
+ LITERAL Float 2.7 42:Root[0000, 0]@28..31#ROOT2024
+
+
+
+ SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024
+ PUNCH - [alone] 42:Root[0000, 0]@0..1#ROOT2024
+ LITERAL Integer 1u16 42:Root[0000, 0]@1..5#ROOT2024
+ PUNCH , [alone] 42:Root[0000, 0]@5..6#ROOT2024
+ PUNCH - [alone] 42:Root[0000, 0]@7..8#ROOT2024
+ LITERAL Integer 2_u32 42:Root[0000, 0]@9..14#ROOT2024
+ PUNCH , [alone] 42:Root[0000, 0]@14..15#ROOT2024
+ PUNCH - [alone] 42:Root[0000, 0]@16..17#ROOT2024
+ LITERAL Float 3.14f32 42:Root[0000, 0]@17..24#ROOT2024
+ PUNCH , [alone] 42:Root[0000, 0]@24..25#ROOT2024
+ PUNCH - [alone] 42:Root[0000, 0]@26..27#ROOT2024
+ LITERAL Float 2.7 42:Root[0000, 0]@28..31#ROOT2024"#]],
);
}
@@ -498,21 +498,21 @@ fn test_attr_macro() {
LITERAL Str #[attr_error(some arguments)] mod m {} 1
PUNCH ; [alone] 1"#]],
expect![[r#"
- SUBTREE $$ 42:[email protected]#ROOT2024 42:[email protected]#ROOT2024
- IDENT mod 42:[email protected]#ROOT2024
- IDENT m 42:[email protected]#ROOT2024
- SUBTREE {} 42:[email protected]#ROOT2024 42:[email protected]#ROOT2024
-
- SUBTREE $$ 42:[email protected]#ROOT2024 42:[email protected]#ROOT2024
- IDENT some 42:[email protected]#ROOT2024
- IDENT arguments 42:[email protected]#ROOT2024
-
- SUBTREE $$ 42:[email protected]#ROOT2024 42:[email protected]#ROOT2024
- IDENT compile_error 42:[email protected]#ROOT2024
- PUNCH ! [alone] 42:[email protected]#ROOT2024
- SUBTREE () 42:[email protected]#ROOT2024 42:[email protected]#ROOT2024
- LITERAL Str #[attr_error(some arguments)] mod m {} 42:[email protected]#ROOT2024
- PUNCH ; [alone] 42:[email protected]#ROOT2024"#]],
+ SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024
+ IDENT mod 42:Root[0000, 0]@0..3#ROOT2024
+ IDENT m 42:Root[0000, 0]@4..5#ROOT2024
+ SUBTREE {} 42:Root[0000, 0]@6..7#ROOT2024 42:Root[0000, 0]@7..8#ROOT2024
+
+ SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024
+ IDENT some 42:Root[0000, 0]@0..4#ROOT2024
+ IDENT arguments 42:Root[0000, 0]@5..14#ROOT2024
+
+ SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024
+ IDENT compile_error 42:Root[0000, 0]@0..100#ROOT2024
+ PUNCH ! [alone] 42:Root[0000, 0]@0..100#ROOT2024
+ SUBTREE () 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024
+ LITERAL Str #[attr_error(some arguments)] mod m {} 42:Root[0000, 0]@0..100#ROOT2024
+ PUNCH ; [alone] 42:Root[0000, 0]@0..100#ROOT2024"#]],
);
}
diff --git a/crates/proc-macro-srv/src/tests/utils.rs b/crates/proc-macro-srv/src/tests/utils.rs
index a0a45b269e..e0a69608de 100644
--- a/crates/proc-macro-srv/src/tests/utils.rs
+++ b/crates/proc-macro-srv/src/tests/utils.rs
@@ -1,7 +1,10 @@
//! utils used in proc-macro tests
use expect_test::Expect;
-use span::{EditionedFileId, ErasedFileAstId, FileId, Span, SpanAnchor, SyntaxContext, TokenId};
+use span::{
+ EditionedFileId, FIXUP_ERASED_FILE_AST_ID_MARKER, FileId, ROOT_ERASED_FILE_AST_ID, Span,
+ SpanAnchor, SyntaxContext, TokenId,
+};
use tt::TextRange;
use crate::{EnvSnapshot, ProcMacroSrv, dylib, proc_macro_test_dylib_path};
@@ -65,8 +68,17 @@ fn assert_expand_impl(
let input_ts_string = format!("{input_ts:?}");
let attr_ts_string = attr_ts.as_ref().map(|it| format!("{it:?}"));
- let res =
- expander.expand(macro_name, input_ts, attr_ts, def_site, call_site, mixed_site).unwrap();
+ let res = expander
+ .expand(
+ macro_name,
+ input_ts,
+ attr_ts,
+ def_site,
+ call_site,
+ mixed_site,
+ FIXUP_ERASED_FILE_AST_ID_MARKER,
+ )
+ .unwrap();
expect.assert_eq(&format!(
"{input_ts_string}\n\n{}\n\n{res:?}",
attr_ts_string.unwrap_or_default()
@@ -76,7 +88,7 @@ fn assert_expand_impl(
range: TextRange::new(0.into(), 150.into()),
anchor: SpanAnchor {
file_id: EditionedFileId::current_edition(FileId::from_raw(41)),
- ast_id: ErasedFileAstId::from_raw(1),
+ ast_id: ROOT_ERASED_FILE_AST_ID,
},
ctx: SyntaxContext::root(span::Edition::CURRENT),
};
@@ -84,7 +96,7 @@ fn assert_expand_impl(
range: TextRange::new(0.into(), 100.into()),
anchor: SpanAnchor {
file_id: EditionedFileId::current_edition(FileId::from_raw(42)),
- ast_id: ErasedFileAstId::from_raw(2),
+ ast_id: ROOT_ERASED_FILE_AST_ID,
},
ctx: SyntaxContext::root(span::Edition::CURRENT),
};
@@ -98,7 +110,17 @@ fn assert_expand_impl(
let fixture_string = format!("{fixture:?}");
let attr_string = attr.as_ref().map(|it| format!("{it:?}"));
- let res = expander.expand(macro_name, fixture, attr, def_site, call_site, mixed_site).unwrap();
+ let res = expander
+ .expand(
+ macro_name,
+ fixture,
+ attr,
+ def_site,
+ call_site,
+ mixed_site,
+ FIXUP_ERASED_FILE_AST_ID_MARKER,
+ )
+ .unwrap();
expect_spanned
.assert_eq(&format!("{fixture_string}\n\n{}\n\n{res:#?}", attr_string.unwrap_or_default()));
}
diff --git a/crates/span/Cargo.toml b/crates/span/Cargo.toml
index b3b401c3db..966962bab3 100644
--- a/crates/span/Cargo.toml
+++ b/crates/span/Cargo.toml
@@ -22,6 +22,9 @@ vfs.workspace = true
syntax.workspace = true
stdx.workspace = true
+[dev-dependencies]
+syntax.workspace = true
+
[features]
default = ["salsa"]
diff --git a/crates/span/src/ast_id.rs b/crates/span/src/ast_id.rs
index 228fba1fa0..51a693ca01 100644
--- a/crates/span/src/ast_id.rs
+++ b/crates/span/src/ast_id.rs
@@ -4,137 +4,534 @@
//! Specifically, it enumerates all items in a file and uses position of a an
//! item as an ID. That way, id's don't change unless the set of items itself
//! changes.
+//!
+//! These IDs are tricky. If one of them invalidates, its interned ID invalidates,
+//! and this can cause *a lot* to be recomputed. For example, if you invalidate the ID
+//! of a struct, and that struct has an impl (any impl!) this will cause the `Self`
+//! type of the impl to invalidate, which will cause the all impls queries to be
+//! invalidated, which will cause every trait solve query in this crate *and* all
+//! transitive reverse dependencies to be invalidated, which is pretty much the worst
+//! thing that can happen incrementality wise.
+//!
+//! So we want these IDs to stay as stable as possible. For top-level items, we store
+//! their kind and name, which should be unique, but since they can still not be, we
+//! also store an index disambiguator. For nested items, we also store the ID of their
+//! parent. For macro calls, we store the macro name and an index. There aren't usually
+//! a lot of macro calls in item position, and invalidation in bodies is not much of
+//! a problem, so this should be enough.
use std::{
any::type_name,
fmt,
- hash::{BuildHasher, BuildHasherDefault, Hash, Hasher},
+ hash::{BuildHasher, Hash, Hasher},
marker::PhantomData,
};
use la_arena::{Arena, Idx, RawIdx};
-use rustc_hash::FxHasher;
-use syntax::{AstNode, AstPtr, SyntaxNode, SyntaxNodePtr, ast};
+use rustc_hash::{FxBuildHasher, FxHashMap};
+use syntax::{
+ AstNode, AstPtr, SyntaxKind, SyntaxNode, SyntaxNodePtr,
+ ast::{self, HasName},
+ match_ast,
+};
+
+// The first index is always the root node's AstId
+/// The root ast id always points to the encompassing file, using this in spans is discouraged as
+/// any range relative to it will be effectively absolute, ruining the entire point of anchored
+/// relative text ranges.
+pub const ROOT_ERASED_FILE_AST_ID: ErasedFileAstId =
+ ErasedFileAstId(pack_hash_index_and_kind(0, 0, ErasedFileAstIdKind::Root as u32));
+
+/// ErasedFileAstId used as the span for syntax node fixups. Any Span containing this file id is to be
+/// considered fake.
+pub const FIXUP_ERASED_FILE_AST_ID_MARKER: ErasedFileAstId =
+ ErasedFileAstId(pack_hash_index_and_kind(0, 0, ErasedFileAstIdKind::Fixup as u32));
-/// See crates\hir-expand\src\ast_id_map.rs
/// This is a type erased FileAstId.
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct ErasedFileAstId(u32);
+impl fmt::Debug for ErasedFileAstId {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let kind = self.kind();
+ macro_rules! kind {
+ ($($kind:ident),* $(,)?) => {
+ if false {
+ // Ensure we covered all variants.
+ match ErasedFileAstIdKind::Root {
+ $( ErasedFileAstIdKind::$kind => {} )*
+ }
+ unreachable!()
+ }
+ $( else if kind == ErasedFileAstIdKind::$kind as u32 {
+ stringify!($kind)
+ } )*
+ else {
+ "Unknown"
+ }
+ };
+ }
+ let kind = kind!(
+ Root,
+ Enum,
+ Struct,
+ Union,
+ ExternCrate,
+ MacroDef,
+ MacroRules,
+ Module,
+ Static,
+ Trait,
+ TraitAlias,
+ Variant,
+ Const,
+ Fn,
+ MacroCall,
+ TypeAlias,
+ ExternBlock,
+ Use,
+ Impl,
+ BlockExpr,
+ Fixup,
+ );
+ if f.alternate() {
+ write!(f, "{kind}[{:04X}, {}]", self.hash_value(), self.index())
+ } else {
+ f.debug_struct("ErasedFileAstId")
+ .field("kind", &format_args!("{kind}"))
+ .field("index", &self.index())
+ .field("hash", &format_args!("{:04X}", self.hash_value()))
+ .finish()
+ }
+ }
+}
+
+#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
+enum ErasedFileAstIdKind {
+ Root,
+ // The following are associated with `ErasedHasNameFileAstId`.
+ Enum,
+ Struct,
+ Union,
+ ExternCrate,
+ MacroDef,
+ MacroRules,
+ Module,
+ Static,
+ Trait,
+ TraitAlias,
+ // Until here associated with `ErasedHasNameFileAstId`.
+ // The following are associated with `ErasedAssocItemFileAstId`.
+ Variant,
+ Const,
+ Fn,
+ MacroCall,
+ TypeAlias,
+ // Until here associated with `ErasedAssocItemFileAstId`.
+ // Extern blocks don't really have any identifying property unfortunately.
+ ExternBlock,
+ // FIXME: If we store the final `UseTree` instead of the top-level `Use`, we can store its name,
+ // and be way more granular for incrementality, at the expense of increased memory usage.
+ // Use IDs aren't used a lot. The main thing that stores them is the def map. So everything that
+ // uses the def map will be invalidated. That includes infers, and so is pretty bad, but our
+ // def map incrementality story is pretty bad anyway and needs to be improved (see
+ // https://rust-lang.zulipchat.com/#narrow/channel/185405-t-compiler.2Frust-analyzer/topic/.60infer.60.20queries.20and.20splitting.20.60DefMap.60).
+ // So I left this as-is for now, as the def map improvement should also mitigate this.
+ Use,
+ /// Associated with [`ImplFileAstId`].
+ Impl,
+ /// Associated with [`BlockExprFileAstId`].
+ BlockExpr,
+ /// Keep this last.
+ Fixup,
+}
+
+// First hash, then index, then kind.
+const HASH_BITS: u32 = 16;
+const INDEX_BITS: u32 = 11;
+const KIND_BITS: u32 = 5;
+const _: () = assert!(ErasedFileAstIdKind::Fixup as u32 <= ((1 << KIND_BITS) - 1));
+const _: () = assert!(HASH_BITS + INDEX_BITS + KIND_BITS == u32::BITS);
+
+#[inline]
+const fn u16_hash(hash: u64) -> u16 {
+ // We do basically the same as `FxHasher`. We don't use rustc-hash and truncate because the
+ // higher bits have more entropy, but unlike rustc-hash we don't rotate because it rotates
+ // for hashmaps that just use the low bits, but we compare all bits.
+ const K: u16 = 0xecc5;
+ let (part1, part2, part3, part4) =
+ (hash as u16, (hash >> 16) as u16, (hash >> 32) as u16, (hash >> 48) as u16);
+ part1
+ .wrapping_add(part2)
+ .wrapping_mul(K)
+ .wrapping_add(part3)
+ .wrapping_mul(K)
+ .wrapping_add(part4)
+ .wrapping_mul(K)
+}
+
+#[inline]
+const fn pack_hash_index_and_kind(hash: u16, index: u32, kind: u32) -> u32 {
+ (hash as u32) | (index << HASH_BITS) | (kind << (HASH_BITS + INDEX_BITS))
+}
+
impl ErasedFileAstId {
- pub const fn into_raw(self) -> u32 {
- self.0
+ #[inline]
+ fn hash_value(self) -> u16 {
+ self.0 as u16
}
- pub const fn from_raw(u32: u32) -> Self {
- Self(u32)
+
+ #[inline]
+ fn index(self) -> u32 {
+ (self.0 << KIND_BITS) >> (HASH_BITS + KIND_BITS)
}
-}
-impl fmt::Display for ErasedFileAstId {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- self.0.fmt(f)
+ #[inline]
+ fn kind(self) -> u32 {
+ self.0 >> (HASH_BITS + INDEX_BITS)
}
-}
-impl fmt::Debug for ErasedFileAstId {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- self.0.fmt(f)
+
+ fn ast_id_for(
+ node: &SyntaxNode,
+ index_map: &mut ErasedAstIdNextIndexMap,
+ parent: Option<&ErasedFileAstId>,
+ ) -> Option<ErasedFileAstId> {
+ // Blocks are deliberately not here - we only want to allocate a block if it contains items.
+ has_name_ast_id(node, index_map)
+ .or_else(|| assoc_item_ast_id(node, index_map, parent))
+ .or_else(|| extern_block_ast_id(node, index_map))
+ .or_else(|| use_ast_id(node, index_map))
+ .or_else(|| impl_ast_id(node, index_map))
+ }
+
+ fn should_alloc(node: &SyntaxNode) -> bool {
+ should_alloc_has_name(node)
+ || should_alloc_assoc_item(node)
+ || ast::ExternBlock::can_cast(node.kind())
+ || ast::Use::can_cast(node.kind())
+ || ast::Impl::can_cast(node.kind())
+ }
+
+ #[inline]
+ pub fn into_raw(self) -> u32 {
+ self.0
+ }
+
+ #[inline]
+ pub fn from_raw(v: u32) -> Self {
+ Self(v)
}
}
+pub trait AstIdNode: AstNode {}
+
/// `AstId` points to an AST node in a specific file.
-pub struct FileAstId<N: AstIdNode> {
+pub struct FileAstId<N> {
raw: ErasedFileAstId,
- covariant: PhantomData<fn() -> N>,
+ _marker: PhantomData<fn() -> N>,
}
-impl<N: AstIdNode> Clone for FileAstId<N> {
+/// Traits are manually implemented because `derive` adds redundant bounds.
+impl<N> Clone for FileAstId<N> {
+ #[inline]
fn clone(&self) -> FileAstId<N> {
*self
}
}
-impl<N: AstIdNode> Copy for FileAstId<N> {}
+impl<N> Copy for FileAstId<N> {}
-impl<N: AstIdNode> PartialEq for FileAstId<N> {
+impl<N> PartialEq for FileAstId<N> {
fn eq(&self, other: &Self) -> bool {
self.raw == other.raw
}
}
-impl<N: AstIdNode> Eq for FileAstId<N> {}
-impl<N: AstIdNode> Hash for FileAstId<N> {
+impl<N> Eq for FileAstId<N> {}
+impl<N> Hash for FileAstId<N> {
fn hash<H: Hasher>(&self, hasher: &mut H) {
self.raw.hash(hasher);
}
}
-impl<N: AstIdNode> fmt::Debug for FileAstId<N> {
+impl<N> fmt::Debug for FileAstId<N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "FileAstId::<{}>({})", type_name::<N>(), self.raw)
+ write!(f, "FileAstId::<{}>({:?})", type_name::<N>(), self.raw)
}
}
-impl<N: AstIdNode> FileAstId<N> {
+impl<N> FileAstId<N> {
// Can't make this a From implementation because of coherence
+ #[inline]
pub fn upcast<M: AstIdNode>(self) -> FileAstId<M>
where
N: Into<M>,
{
- FileAstId { raw: self.raw, covariant: PhantomData }
+ FileAstId { raw: self.raw, _marker: PhantomData }
}
+ #[inline]
pub fn erase(self) -> ErasedFileAstId {
self.raw
}
}
-pub trait AstIdNode: AstNode {}
-macro_rules! register_ast_id_node {
+#[derive(Hash)]
+struct ErasedHasNameFileAstId<'a> {
+ kind: SyntaxKind,
+ name: &'a str,
+}
+
+/// This holds the ast ID for variants too (they're a kind of assoc item).
+#[derive(Hash)]
+struct ErasedAssocItemFileAstId<'a> {
+ /// Subtle: items in `extern` blocks **do not** store the ID of the extern block here.
+ /// Instead this is left empty. The reason is that `ExternBlockFileAstId` is pretty unstable
+ /// (it contains only an index), and extern blocks don't introduce a new scope, so storing
+ /// the extern block ID will do more harm to incrementality than help.
+ parent: Option<ErasedFileAstId>,
+ properties: ErasedHasNameFileAstId<'a>,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+struct ImplFileAstId<'a> {
+ /// This can be `None` if the `Self` type is not a named type, or if it is inside a macro call.
+ self_ty_name: Option<&'a str>,
+ /// This can be `None` if this is an inherent impl, or if the trait name is inside a macro call.
+ trait_name: Option<&'a str>,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+struct BlockExprFileAstId {
+ parent: Option<ErasedFileAstId>,
+}
+
+impl AstIdNode for ast::ExternBlock {}
+
+fn extern_block_ast_id(
+ node: &SyntaxNode,
+ index_map: &mut ErasedAstIdNextIndexMap,
+) -> Option<ErasedFileAstId> {
+ if ast::ExternBlock::can_cast(node.kind()) {
+ Some(index_map.new_id(ErasedFileAstIdKind::ExternBlock, ()))
+ } else {
+ None
+ }
+}
+
+impl AstIdNode for ast::Use {}
+
+fn use_ast_id(
+ node: &SyntaxNode,
+ index_map: &mut ErasedAstIdNextIndexMap,
+) -> Option<ErasedFileAstId> {
+ if ast::Use::can_cast(node.kind()) {
+ Some(index_map.new_id(ErasedFileAstIdKind::Use, ()))
+ } else {
+ None
+ }
+}
+
+impl AstIdNode for ast::Impl {}
+
+fn impl_ast_id(
+ node: &SyntaxNode,
+ index_map: &mut ErasedAstIdNextIndexMap,
+) -> Option<ErasedFileAstId> {
+ if let Some(node) = ast::Impl::cast(node.clone()) {
+ let type_as_name = |ty: Option<ast::Type>| match ty? {
+ ast::Type::PathType(it) => Some(it.path()?.segment()?.name_ref()?),
+ _ => None,
+ };
+ let self_ty_name = type_as_name(node.self_ty());
+ let trait_name = type_as_name(node.trait_());
+ let data = ImplFileAstId {
+ self_ty_name: self_ty_name.as_ref().map(|it| it.text_non_mutable()),
+ trait_name: trait_name.as_ref().map(|it| it.text_non_mutable()),
+ };
+ Some(index_map.new_id(ErasedFileAstIdKind::Impl, data))
+ } else {
+ None
+ }
+}
+
+// Blocks aren't `AstIdNode`s deliberately, because unlike other nodes, not all blocks get their own
+// ast id, only if they have items. To account for that we have a different, fallible, API for blocks.
+// impl !AstIdNode for ast::BlockExpr {}
+
+fn block_expr_ast_id(
+ node: &SyntaxNode,
+ index_map: &mut ErasedAstIdNextIndexMap,
+ parent: Option<&ErasedFileAstId>,
+) -> Option<ErasedFileAstId> {
+ if ast::BlockExpr::can_cast(node.kind()) {
+ Some(
+ index_map.new_id(
+ ErasedFileAstIdKind::BlockExpr,
+ BlockExprFileAstId { parent: parent.copied() },
+ ),
+ )
+ } else {
+ None
+ }
+}
+
+#[derive(Default)]
+struct ErasedAstIdNextIndexMap(FxHashMap<(ErasedFileAstIdKind, u16), u32>);
+
+impl ErasedAstIdNextIndexMap {
+ #[inline]
+ fn new_id(&mut self, kind: ErasedFileAstIdKind, data: impl Hash) -> ErasedFileAstId {
+ let hash = FxBuildHasher.hash_one(&data);
+ let initial_hash = u16_hash(hash);
+ // Even though 2^INDEX_BITS=2048 items with the same hash seems like a lot,
+ // it could happen with macro calls or `use`s in macro-generated files. So we want
+ // to handle it gracefully. We just increment the hash.
+ let mut hash = initial_hash;
+ let index = loop {
+ match self.0.entry((kind, hash)) {
+ std::collections::hash_map::Entry::Occupied(mut entry) => {
+ let i = entry.get_mut();
+ if *i < ((1 << INDEX_BITS) - 1) {
+ *i += 1;
+ break *i;
+ }
+ }
+ std::collections::hash_map::Entry::Vacant(entry) => {
+ entry.insert(0);
+ break 0;
+ }
+ }
+ hash = hash.wrapping_add(1);
+ if hash == initial_hash {
+ // That's 2^27=134,217,728 items!
+ panic!("you have way too many items in the same file!");
+ }
+ };
+ let kind = kind as u32;
+ ErasedFileAstId(pack_hash_index_and_kind(hash, index, kind))
+ }
+}
+
+macro_rules! register_enum_ast_id {
(impl AstIdNode for $($ident:ident),+ ) => {
$(
impl AstIdNode for ast::$ident {}
)+
- fn should_alloc_id(kind: syntax::SyntaxKind) -> bool {
- $(
- ast::$ident::can_cast(kind)
- )||+
+ };
+}
+register_enum_ast_id! {
+ impl AstIdNode for
+ Item, AnyHasGenericParams, Adt, Macro,
+ AssocItem
+}
+
+macro_rules! register_has_name_ast_id {
+ (impl AstIdNode for $($ident:ident = $name_method:ident),+ ) => {
+ $(
+ impl AstIdNode for ast::$ident {}
+ )+
+
+ fn has_name_ast_id(node: &SyntaxNode, index_map: &mut ErasedAstIdNextIndexMap) -> Option<ErasedFileAstId> {
+ let kind = node.kind();
+ match_ast! {
+ match node {
+ $(
+ ast::$ident(node) => {
+ let name = node.$name_method();
+ let name = name.as_ref().map_or("", |it| it.text_non_mutable());
+ let result = ErasedHasNameFileAstId {
+ kind,
+ name,
+ };
+ Some(index_map.new_id(ErasedFileAstIdKind::$ident, result))
+ },
+ )*
+ _ => None,
+ }
+ }
+ }
+
+ fn should_alloc_has_name(node: &SyntaxNode) -> bool {
+ let kind = node.kind();
+ false $( || ast::$ident::can_cast(kind) )*
}
};
}
-register_ast_id_node! {
+register_has_name_ast_id! {
impl AstIdNode for
- Item, AnyHasGenericParams,
- Adt,
- Enum,
- Variant,
- Struct,
- Union,
- AssocItem,
- Const,
- Fn,
- MacroCall,
- TypeAlias,
- ExternBlock,
- ExternCrate,
- Impl,
- Macro,
- MacroDef,
- MacroRules,
- Module,
- Static,
- Trait,
- TraitAlias,
- Use,
- BlockExpr, ConstArg
+ Enum = name,
+ Struct = name,
+ Union = name,
+ ExternCrate = name_ref,
+ MacroDef = name,
+ MacroRules = name,
+ Module = name,
+ Static = name,
+ Trait = name,
+ TraitAlias = name
+}
+
+macro_rules! register_assoc_item_ast_id {
+ (impl AstIdNode for $($ident:ident = $name_callback:expr),+ ) => {
+ $(
+ impl AstIdNode for ast::$ident {}
+ )+
+
+ fn assoc_item_ast_id(
+ node: &SyntaxNode,
+ index_map: &mut ErasedAstIdNextIndexMap,
+ parent: Option<&ErasedFileAstId>,
+ ) -> Option<ErasedFileAstId> {
+ let kind = node.kind();
+ match_ast! {
+ match node {
+ $(
+ ast::$ident(node) => {
+ let name = $name_callback(node);
+ let name = name.as_ref().map_or("", |it| it.text_non_mutable());
+ let properties = ErasedHasNameFileAstId {
+ kind,
+ name,
+ };
+ let result = ErasedAssocItemFileAstId {
+ parent: parent.copied(),
+ properties,
+ };
+ Some(index_map.new_id(ErasedFileAstIdKind::$ident, result))
+ },
+ )*
+ _ => None,
+ }
+ }
+ }
+
+ fn should_alloc_assoc_item(node: &SyntaxNode) -> bool {
+ let kind = node.kind();
+ false $( || ast::$ident::can_cast(kind) )*
+ }
+ };
+}
+register_assoc_item_ast_id! {
+ impl AstIdNode for
+ Variant = |it: ast::Variant| it.name(),
+ Const = |it: ast::Const| it.name(),
+ Fn = |it: ast::Fn| it.name(),
+ MacroCall = |it: ast::MacroCall| it.path().and_then(|path| path.segment()?.name_ref()),
+ TypeAlias = |it: ast::TypeAlias| it.name()
}
/// Maps items' `SyntaxNode`s to `ErasedFileAstId`s and back.
#[derive(Default)]
pub struct AstIdMap {
- /// Maps stable id to unstable ptr.
- arena: Arena<SyntaxNodePtr>,
- /// Reverse: map ptr to id.
- map: hashbrown::HashTable<Idx<SyntaxNodePtr>>,
+ /// An arena of the ptrs and their associated ID.
+ arena: Arena<(SyntaxNodePtr, ErasedFileAstId)>,
+ /// Map ptr to id.
+ ptr_map: hashbrown::HashTable<ArenaId>,
+ /// Map id to ptr.
+ id_map: hashbrown::HashTable<ArenaId>,
}
+type ArenaId = Idx<(SyntaxNodePtr, ErasedFileAstId)>;
+
impl fmt::Debug for AstIdMap {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("AstIdMap").field("arena", &self.arena).finish()
@@ -148,31 +545,116 @@ impl PartialEq for AstIdMap {
}
impl Eq for AstIdMap {}
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+enum ContainsItems {
+ Yes,
+ No,
+}
+
impl AstIdMap {
pub fn from_source(node: &SyntaxNode) -> AstIdMap {
assert!(node.parent().is_none());
let mut res = AstIdMap::default();
+ let mut index_map = ErasedAstIdNextIndexMap::default();
+
+ // Ensure we allocate the root.
+ res.arena.alloc((SyntaxNodePtr::new(node), ROOT_ERASED_FILE_AST_ID));
- // make sure to allocate the root node
- if !should_alloc_id(node.kind()) {
- res.alloc(node);
- }
// By walking the tree in breadth-first order we make sure that parents
// get lower ids then children. That is, adding a new child does not
// change parent's id. This means that, say, adding a new function to a
// trait does not change ids of top-level items, which helps caching.
- bdfs(node, |it| {
- if should_alloc_id(it.kind()) {
- res.alloc(&it);
- TreeOrder::BreadthFirst
- } else {
- TreeOrder::DepthFirst
+
+ // This contains the stack of the `BlockExpr`s we are under. We do this
+ // so we only allocate `BlockExpr`s if they contain items.
+ // The general idea is: when we enter a block we push `(block, false)` here.
+ // Items inside the block are attributed to the block's container, not the block.
+ // For the first item we find inside a block, we make this `(block, true)`
+ // and create an ast id for the block. When exiting the block we pop it,
+ // whether or not we created an ast id for it.
+ // It may seem that with this setup we will generate an ID for blocks that
+ // have no items directly but have items inside other items inside them.
+ // This is true, but it doesn't matter, because such blocks can't exist.
+ // After all, the block will then contain the *outer* item, so we allocate
+ // an ID for it anyway.
+ let mut blocks = Vec::new();
+ let mut curr_layer = vec![(node.clone(), None)];
+ let mut next_layer = vec![];
+ while !curr_layer.is_empty() {
+ curr_layer.drain(..).for_each(|(node, parent_idx)| {
+ let mut preorder = node.preorder();
+ while let Some(event) = preorder.next() {
+ match event {
+ syntax::WalkEvent::Enter(node) => {
+ if ast::BlockExpr::can_cast(node.kind()) {
+ blocks.push((node, ContainsItems::No));
+ } else if ErasedFileAstId::should_alloc(&node) {
+ // Allocate blocks on-demand, only if they have items.
+ // We don't associate items with blocks, only with items, since block IDs can be quite unstable.
+ // FIXME: Is this the correct thing to do? Macro calls might actually be more incremental if
+ // associated with blocks (not sure). Either way it's not a big deal.
+ if let Some((
+ last_block_node,
+ already_allocated @ ContainsItems::No,
+ )) = blocks.last_mut()
+ {
+ let block_ast_id = block_expr_ast_id(
+ last_block_node,
+ &mut index_map,
+ parent_of(parent_idx, &res),
+ )
+ .expect("not a BlockExpr");
+ res.arena
+ .alloc((SyntaxNodePtr::new(last_block_node), block_ast_id));
+ *already_allocated = ContainsItems::Yes;
+ }
+
+ let parent = parent_of(parent_idx, &res);
+ let ast_id =
+ ErasedFileAstId::ast_id_for(&node, &mut index_map, parent)
+ .expect("this node should have an ast id");
+ let idx = res.arena.alloc((SyntaxNodePtr::new(&node), ast_id));
+
+ next_layer.extend(node.children().map(|child| (child, Some(idx))));
+ preorder.skip_subtree();
+ }
+ }
+ syntax::WalkEvent::Leave(node) => {
+ if ast::BlockExpr::can_cast(node.kind()) {
+ assert_eq!(
+ blocks.pop().map(|it| it.0),
+ Some(node),
+ "left a BlockExpr we never entered"
+ );
+ }
+ }
+ }
+ }
+ });
+ std::mem::swap(&mut curr_layer, &mut next_layer);
+ assert!(blocks.is_empty(), "didn't leave all BlockExprs");
+ }
+
+ res.ptr_map = hashbrown::HashTable::with_capacity(res.arena.len());
+ res.id_map = hashbrown::HashTable::with_capacity(res.arena.len());
+ for (idx, (ptr, ast_id)) in res.arena.iter() {
+ let ptr_hash = hash_ptr(ptr);
+ let ast_id_hash = hash_ast_id(ast_id);
+ match res.ptr_map.entry(
+ ptr_hash,
+ |idx2| *idx2 == idx,
+ |&idx| hash_ptr(&res.arena[idx].0),
+ ) {
+ hashbrown::hash_table::Entry::Occupied(_) => unreachable!(),
+ hashbrown::hash_table::Entry::Vacant(entry) => {
+ entry.insert(idx);
+ }
}
- });
- res.map = hashbrown::HashTable::with_capacity(res.arena.len());
- for (idx, ptr) in res.arena.iter() {
- let hash = hash_ptr(ptr);
- match res.map.entry(hash, |&idx2| idx2 == idx, |&idx| hash_ptr(&res.arena[idx])) {
+ match res.id_map.entry(
+ ast_id_hash,
+ |idx2| *idx2 == idx,
+ |&idx| hash_ast_id(&res.arena[idx].1),
+ ) {
hashbrown::hash_table::Entry::Occupied(_) => unreachable!(),
hashbrown::hash_table::Entry::Vacant(entry) => {
entry.insert(idx);
@@ -180,98 +662,235 @@ impl AstIdMap {
}
}
res.arena.shrink_to_fit();
- res
+ return res;
+
+ fn parent_of(parent_idx: Option<ArenaId>, res: &AstIdMap) -> Option<&ErasedFileAstId> {
+ let mut parent = parent_idx.map(|parent_idx| &res.arena[parent_idx].1);
+ if parent.is_some_and(|parent| parent.kind() == ErasedFileAstIdKind::ExternBlock as u32)
+ {
+ // See the comment on `ErasedAssocItemFileAstId` for why is this.
+ // FIXME: Technically there could be an extern block inside another item, e.g.:
+ // ```
+ // fn foo() {
+ // extern "C" {
+ // fn bar();
+ // }
+ // }
+ // ```
+ // Here we want to make `foo()` the parent of `bar()`, but we make it `None`.
+ // Shouldn't be a big deal though.
+ parent = None;
+ }
+ parent
+ }
}
/// The [`AstId`] of the root node
pub fn root(&self) -> SyntaxNodePtr {
- self.arena[Idx::from_raw(RawIdx::from_u32(0))]
+ self.arena[Idx::from_raw(RawIdx::from_u32(0))].0
}
pub fn ast_id<N: AstIdNode>(&self, item: &N) -> FileAstId<N> {
- let raw = self.erased_ast_id(item.syntax());
- FileAstId { raw, covariant: PhantomData }
+ self.ast_id_for_ptr(AstPtr::new(item))
+ }
+
+ /// Blocks may not be allocated (if they have no items), so they have a different API.
+ pub fn ast_id_for_block(&self, block: &ast::BlockExpr) -> Option<FileAstId<ast::BlockExpr>> {
+ self.ast_id_for_ptr_for_block(AstPtr::new(block))
}
pub fn ast_id_for_ptr<N: AstIdNode>(&self, ptr: AstPtr<N>) -> FileAstId<N> {
let ptr = ptr.syntax_node_ptr();
- let hash = hash_ptr(&ptr);
- match self.map.find(hash, |&idx| self.arena[idx] == ptr) {
- Some(&raw) => FileAstId {
- raw: ErasedFileAstId(raw.into_raw().into_u32()),
- covariant: PhantomData,
- },
- None => panic!(
- "Can't find {:?} in AstIdMap:\n{:?}",
+ FileAstId { raw: self.erased_ast_id(ptr), _marker: PhantomData }
+ }
+
+ /// Blocks may not be allocated (if they have no items), so they have a different API.
+ pub fn ast_id_for_ptr_for_block(
+ &self,
+ ptr: AstPtr<ast::BlockExpr>,
+ ) -> Option<FileAstId<ast::BlockExpr>> {
+ let ptr = ptr.syntax_node_ptr();
+ self.try_erased_ast_id(ptr).map(|raw| FileAstId { raw, _marker: PhantomData })
+ }
+
+ fn erased_ast_id(&self, ptr: SyntaxNodePtr) -> ErasedFileAstId {
+ self.try_erased_ast_id(ptr).unwrap_or_else(|| {
+ panic!(
+ "Can't find SyntaxNodePtr {:?} in AstIdMap:\n{:?}",
ptr,
self.arena.iter().map(|(_id, i)| i).collect::<Vec<_>>(),
- ),
- }
+ )
+ })
}
- pub fn get<N: AstIdNode>(&self, id: FileAstId<N>) -> AstPtr<N> {
- AstPtr::try_from_raw(self.arena[Idx::from_raw(RawIdx::from_u32(id.raw.into_raw()))])
- .unwrap()
+ fn try_erased_ast_id(&self, ptr: SyntaxNodePtr) -> Option<ErasedFileAstId> {
+ let hash = hash_ptr(&ptr);
+ let idx = *self.ptr_map.find(hash, |&idx| self.arena[idx].0 == ptr)?;
+ Some(self.arena[idx].1)
}
- pub fn get_erased(&self, id: ErasedFileAstId) -> SyntaxNodePtr {
- self.arena[Idx::from_raw(RawIdx::from_u32(id.into_raw()))]
+ // Don't bound on `AstIdNode` here, because `BlockExpr`s are also valid here (`ast::BlockExpr`
+ // doesn't always have a matching `FileAstId`, but a `FileAstId<ast::BlockExpr>` always has
+ // a matching node).
+ pub fn get<N: AstNode>(&self, id: FileAstId<N>) -> AstPtr<N> {
+ let ptr = self.get_erased(id.raw);
+ AstPtr::try_from_raw(ptr)
+ .unwrap_or_else(|| panic!("AstIdMap node mismatch with node `{ptr:?}`"))
}
- fn erased_ast_id(&self, item: &SyntaxNode) -> ErasedFileAstId {
- let ptr = SyntaxNodePtr::new(item);
- let hash = hash_ptr(&ptr);
- match self.map.find(hash, |&idx| self.arena[idx] == ptr) {
- Some(&idx) => ErasedFileAstId(idx.into_raw().into_u32()),
+ pub fn get_erased(&self, id: ErasedFileAstId) -> SyntaxNodePtr {
+ let hash = hash_ast_id(&id);
+ match self.id_map.find(hash, |&idx| self.arena[idx].1 == id) {
+ Some(&idx) => self.arena[idx].0,
None => panic!(
- "Can't find {:?} in AstIdMap:\n{:?}\n source text: {}",
- item,
+ "Can't find ast id {:?} in AstIdMap:\n{:?}",
+ id,
self.arena.iter().map(|(_id, i)| i).collect::<Vec<_>>(),
- item
),
}
}
-
- fn alloc(&mut self, item: &SyntaxNode) -> ErasedFileAstId {
- ErasedFileAstId(self.arena.alloc(SyntaxNodePtr::new(item)).into_raw().into_u32())
- }
}
+#[inline]
fn hash_ptr(ptr: &SyntaxNodePtr) -> u64 {
- BuildHasherDefault::<FxHasher>::default().hash_one(ptr)
-}
-
-#[derive(Copy, Clone, PartialEq, Eq)]
-enum TreeOrder {
- BreadthFirst,
- DepthFirst,
-}
-
-/// Walks the subtree in bdfs order, calling `f` for each node. What is bdfs
-/// order? It is a mix of breadth-first and depth first orders. Nodes for which
-/// `f` returns [`TreeOrder::BreadthFirst`] are visited breadth-first, all the other nodes are explored
-/// [`TreeOrder::DepthFirst`].
-///
-/// In other words, the size of the bfs queue is bound by the number of "true"
-/// nodes.
-fn bdfs(node: &SyntaxNode, mut f: impl FnMut(SyntaxNode) -> TreeOrder) {
- let mut curr_layer = vec![node.clone()];
- let mut next_layer = vec![];
- while !curr_layer.is_empty() {
- curr_layer.drain(..).for_each(|node| {
- let mut preorder = node.preorder();
- while let Some(event) = preorder.next() {
- match event {
- syntax::WalkEvent::Enter(node) => {
- if f(node.clone()) == TreeOrder::BreadthFirst {
- next_layer.extend(node.children());
- preorder.skip_subtree();
- }
- }
- syntax::WalkEvent::Leave(_) => {}
- }
+ FxBuildHasher.hash_one(ptr)
+}
+
+#[inline]
+fn hash_ast_id(ptr: &ErasedFileAstId) -> u64 {
+ FxBuildHasher.hash_one(ptr)
+}
+
+#[cfg(test)]
+mod tests {
+ use syntax::{AstNode, Edition, SourceFile, SyntaxKind, SyntaxNodePtr, WalkEvent, ast};
+
+ use crate::AstIdMap;
+
+ #[test]
+ fn check_all_nodes() {
+ let syntax = SourceFile::parse(
+ r#"
+extern crate foo;
+fn foo() {
+ union U {}
+}
+struct S;
+macro_rules! m {}
+macro m2() {}
+trait Trait {}
+impl Trait for S {}
+impl S {}
+impl m!() {}
+impl m2!() for m!() {}
+type T = i32;
+enum E {
+ V1(),
+ V2 {},
+ V3,
+}
+struct S; // duplicate
+extern "C" {
+ static S: i32;
+}
+static mut S: i32 = 0;
+const FOO: i32 = 0;
+ "#,
+ Edition::CURRENT,
+ )
+ .syntax_node();
+ let ast_id_map = AstIdMap::from_source(&syntax);
+ for node in syntax.preorder() {
+ let WalkEvent::Enter(node) = node else { continue };
+ if !matches!(
+ node.kind(),
+ SyntaxKind::EXTERN_CRATE
+ | SyntaxKind::FN
+ | SyntaxKind::UNION
+ | SyntaxKind::STRUCT
+ | SyntaxKind::MACRO_RULES
+ | SyntaxKind::MACRO_DEF
+ | SyntaxKind::MACRO_CALL
+ | SyntaxKind::TRAIT
+ | SyntaxKind::IMPL
+ | SyntaxKind::TYPE_ALIAS
+ | SyntaxKind::ENUM
+ | SyntaxKind::VARIANT
+ | SyntaxKind::EXTERN_BLOCK
+ | SyntaxKind::STATIC
+ | SyntaxKind::CONST
+ ) {
+ continue;
}
- });
- std::mem::swap(&mut curr_layer, &mut next_layer);
+ let ptr = SyntaxNodePtr::new(&node);
+ let ast_id = ast_id_map.erased_ast_id(ptr);
+ let turn_back = ast_id_map.get_erased(ast_id);
+ assert_eq!(ptr, turn_back);
+ }
+ }
+
+ #[test]
+ fn different_names_get_different_hashes() {
+ let syntax = SourceFile::parse(
+ r#"
+fn foo() {}
+fn bar() {}
+ "#,
+ Edition::CURRENT,
+ )
+ .syntax_node();
+ let ast_id_map = AstIdMap::from_source(&syntax);
+ let fns = syntax.descendants().filter_map(ast::Fn::cast).collect::<Vec<_>>();
+ let [foo_fn, bar_fn] = fns.as_slice() else {
+ panic!("not exactly 2 functions");
+ };
+ let foo_fn_id = ast_id_map.ast_id(foo_fn);
+ let bar_fn_id = ast_id_map.ast_id(bar_fn);
+ assert_ne!(foo_fn_id.raw.hash_value(), bar_fn_id.raw.hash_value(), "hashes are equal");
+ }
+
+ #[test]
+ fn different_parents_get_different_hashes() {
+ let syntax = SourceFile::parse(
+ r#"
+fn foo() {
+ m!();
+}
+fn bar() {
+ m!();
+}
+ "#,
+ Edition::CURRENT,
+ )
+ .syntax_node();
+ let ast_id_map = AstIdMap::from_source(&syntax);
+ let macro_calls = syntax.descendants().filter_map(ast::MacroCall::cast).collect::<Vec<_>>();
+ let [macro_call_foo, macro_call_bar] = macro_calls.as_slice() else {
+ panic!("not exactly 2 macro calls");
+ };
+ let macro_call_foo_id = ast_id_map.ast_id(macro_call_foo);
+ let macro_call_bar_id = ast_id_map.ast_id(macro_call_bar);
+ assert_ne!(
+ macro_call_foo_id.raw.hash_value(),
+ macro_call_bar_id.raw.hash_value(),
+ "hashes are equal"
+ );
+ }
+
+ #[test]
+ fn blocks_with_no_items_have_no_id() {
+ let syntax = SourceFile::parse(
+ r#"
+fn foo() {
+ let foo = 1;
+ bar(foo);
+}
+ "#,
+ Edition::CURRENT,
+ )
+ .syntax_node();
+ let ast_id_map = AstIdMap::from_source(&syntax);
+ let block = syntax.descendants().find_map(ast::BlockExpr::cast).expect("no block");
+ assert!(ast_id_map.ast_id_for_block(&block).is_none());
}
}
diff --git a/crates/span/src/lib.rs b/crates/span/src/lib.rs
index f81648ac42..b81d08eed6 100644
--- a/crates/span/src/lib.rs
+++ b/crates/span/src/lib.rs
@@ -6,7 +6,10 @@ mod hygiene;
mod map;
pub use self::{
- ast_id::{AstIdMap, AstIdNode, ErasedFileAstId, FileAstId},
+ ast_id::{
+ AstIdMap, AstIdNode, ErasedFileAstId, FIXUP_ERASED_FILE_AST_ID_MARKER, FileAstId,
+ ROOT_ERASED_FILE_AST_ID,
+ },
hygiene::{SyntaxContext, Transparency},
map::{RealSpanMap, SpanMap},
};
@@ -15,19 +18,6 @@ pub use syntax::Edition;
pub use text_size::{TextRange, TextSize};
pub use vfs::FileId;
-// The first index is always the root node's AstId
-/// The root ast id always points to the encompassing file, using this in spans is discouraged as
-/// any range relative to it will be effectively absolute, ruining the entire point of anchored
-/// relative text ranges.
-pub const ROOT_ERASED_FILE_AST_ID: ErasedFileAstId = ErasedFileAstId::from_raw(0);
-
-/// FileId used as the span for syntax node fixups. Any Span containing this file id is to be
-/// considered fake.
-pub const FIXUP_ERASED_FILE_AST_ID_MARKER: ErasedFileAstId =
- // we pick the second to last for this in case we ever consider making this a NonMaxU32, this
- // is required to be stable for the proc-macro-server
- ErasedFileAstId::from_raw(!0 - 1);
-
pub type Span = SpanData<SyntaxContext>;
impl Span {
@@ -60,7 +50,7 @@ impl<Ctx: fmt::Debug> fmt::Debug for SpanData<Ctx> {
if f.alternate() {
fmt::Debug::fmt(&self.anchor.file_id.file_id().index(), f)?;
f.write_char(':')?;
- fmt::Debug::fmt(&self.anchor.ast_id.into_raw(), f)?;
+ write!(f, "{:#?}", self.anchor.ast_id)?;
f.write_char('@')?;
fmt::Debug::fmt(&self.range, f)?;
f.write_char('#')?;
@@ -85,7 +75,7 @@ impl fmt::Display for Span {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self.anchor.file_id.file_id().index(), f)?;
f.write_char(':')?;
- fmt::Debug::fmt(&self.anchor.ast_id.into_raw(), f)?;
+ write!(f, "{:#?}", self.anchor.ast_id)?;
f.write_char('@')?;
fmt::Debug::fmt(&self.range, f)?;
f.write_char('#')?;
@@ -101,7 +91,7 @@ pub struct SpanAnchor {
impl fmt::Debug for SpanAnchor {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_tuple("SpanAnchor").field(&self.file_id).field(&self.ast_id.into_raw()).finish()
+ f.debug_tuple("SpanAnchor").field(&self.file_id).field(&self.ast_id).finish()
}
}
diff --git a/crates/span/src/map.rs b/crates/span/src/map.rs
index cc7a886643..f58201793d 100644
--- a/crates/span/src/map.rs
+++ b/crates/span/src/map.rs
@@ -169,7 +169,7 @@ impl fmt::Display for RealSpanMap {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "RealSpanMap({:?}):", self.file_id)?;
for span in self.pairs.iter() {
- writeln!(f, "{}: {}", u32::from(span.0), span.1.into_raw())?;
+ writeln!(f, "{}: {:#?}", u32::from(span.0), span.1)?;
}
Ok(())
}
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs
index dcf853427e..f5530c5fff 100644
--- a/crates/syntax/src/ast/node_ext.rs
+++ b/crates/syntax/src/ast/node_ext.rs
@@ -30,6 +30,16 @@ impl ast::Name {
pub fn text(&self) -> TokenText<'_> {
text_of_first_token(self.syntax())
}
+ pub fn text_non_mutable(&self) -> &str {
+ fn first_token(green_ref: &GreenNodeData) -> &GreenTokenData {
+ green_ref.children().next().and_then(NodeOrToken::into_token).unwrap()
+ }
+
+ match self.syntax().green() {
+ Cow::Borrowed(green_ref) => first_token(green_ref).text(),
+ Cow::Owned(_) => unreachable!(),
+ }
+ }
}
impl ast::NameRef {