diff --git a/.typos.toml b/.typos.toml index e938bddd4b12..cdbc003a8088 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 bb6222b1d464..a7328809a823 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> { 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>, -) -> 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 + 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 4a9a3b12cfab..f5aa6821b18a 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, Arc); + // 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 { self.enum_variants_with_diagnostics(id).0 @@ -263,6 +268,9 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + SourceDatabase { e: TypeAliasId, ) -> (Arc, Arc); + #[salsa::invoke(crate::signatures::extern_block_abi_query)] + fn extern_block_abi(&self, extern_block: ExternBlockId) -> Option; + // endregion:data #[salsa::invoke(Body::body_with_source_map_query)] @@ -334,6 +342,9 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + SourceDatabase { #[salsa::invoke(visibility::type_alias_visibility_query)] fn type_alias_visibility(&self, def: TypeAliasId) -> Visibility; + #[salsa::invoke(visibility::trait_visibility_query)] + fn trait_visibility(&self, def: TraitId) -> Visibility; + // endregion:visibilities #[salsa::invoke(crate::lang_item::notable_traits_in_deps)] @@ -399,10 +410,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 +425,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 +436,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 +449,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 3823fb5a1e75..23b9712d1e6c 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 29871f5e04db..89eeaf00bc3d 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, Box<[Statement]>, Option) -> 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 f12a9b7a5445..7b452721dfe2 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(db: &dyn DefDatabase, id: Id, default: &str) -> String +where + Id: Lookup, + 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, "")), + DefWithBodyId::StaticId(it) => format!("static {} = ", item_name(db, it, "")), + DefWithBodyId::ConstId(it) => format!("const {} = ", item_name(db, it, "_")), + DefWithBodyId::VariantId(it) => format!( + "enum {}::{}", + item_name(db, it.lookup(db).parent, ""), + item_name(db, it, "") + ), }; 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, "")), + VariantId::EnumVariantId(it) => format!( + "enum {}::{}", + item_name(db, it.lookup(db).parent, ""), + item_name(db, it, "") + ), + VariantId::UnionId(it) => format!("union {}", item_name(db, it, "")), }; 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, "")); }}; } match *it { diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs index 1b97eb72b6f2..07d1500fc097 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, unions: Arena, enums: Arena, - variants: Arena, consts: Arena, statics: Arena, traits: Arena, @@ -338,41 +336,15 @@ pub enum AttrOwner { ModItem(ModItem), /// Inner attributes of the source file. TopLevel, - - Variant(FileItemTreeId), - // 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 for AttrOwner { + #[inline] + fn from(value: ModItem) -> Self { + AttrOwner::ModItem(value) } } -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub enum FieldParent { - Struct(FileItemTreeId), - Union(FileItemTreeId), - EnumVariant(FileItemTreeId), -} - -pub type ItemTreeFieldId = Idx; - -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)); - /// 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; - fn attr_owner(id: FileItemTreeId) -> AttrOwner; } pub struct FileItemTreeId(Idx); @@ -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 { &tree.data().$fld[index] } - - fn attr_owner(id: FileItemTreeId) -> AttrOwner { - AttrOwner::ModItem(ModItem::$typ(id)) - } } impl Index> for ItemTree { @@ -621,22 +589,6 @@ impl Index> for ItemTree { } } -impl ItemTreeNode for Variant { - type Source = ast::Variant; - - fn ast_id(&self) -> FileAstId { - self.ast_id - } - - fn lookup(tree: &ItemTree, index: Idx) -> &Self { - &tree.data().variants[index] - } - - fn attr_owner(id: FileItemTreeId) -> 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, pub ast_id: FileAstId, 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, } @@ -734,7 +684,6 @@ pub struct Struct { pub struct Union { pub name: Name, pub visibility: RawVisibilityId, - pub fields: Box<[Field]>, pub ast_id: FileAstId, } @@ -742,18 +691,9 @@ pub struct Union { pub struct Enum { pub name: Name, pub visibility: RawVisibilityId, - pub variants: Range>, pub ast_id: FileAstId, } -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Variant { - pub name: Name, - pub fields: Box<[Field]>, - pub shape: FieldsShape, - pub ast_id: FileAstId, -} - #[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, } @@ -827,7 +756,6 @@ pub struct TraitAlias { #[derive(Debug, Clone, Eq, PartialEq)] pub struct Impl { - pub items: Box<[AssocItem]>, pub ast_id: FileAstId, } @@ -878,43 +806,6 @@ pub struct Macro2 { pub ast_id: FileAstId, } -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 { - // 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 { - // 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 { - 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), - TypeAlias(FileItemTreeId), - Const(FileItemTreeId), - MacroCall(FileItemTreeId), -} - -impl_froms!(AssocItem { - Function(FileItemTreeId), - TypeAlias(FileItemTreeId), - Const(FileItemTreeId), - MacroCall(FileItemTreeId), -}); - -impl From 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 { - 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 b490e1683c01..d9588cb487d6 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 { - 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> { 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> { 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> { - 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 { - 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> { 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 { 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 { 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 { - 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, 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 47c6eb13293f..0c62b86dae28 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 824fbfa5921a..e9e10dd9a079 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[B484, 0] pub(self) extern crate self as renamed; - // AstId: 2 + // AstId: ExternCrate[B4FC, 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[347F, 0] pub(self) type ExType; #[on_extern_static] - // AstId: 3 + // AstId: Static[D0BC, 0] pub(self) static EX_STATIC = _; #[on_extern_fn] - // AstId: 4 + // AstId: Fn[DB5F, 0] pub(self) fn ex_fn; } - "##]], + "#]], ); } @@ -124,44 +124,21 @@ enum E { } "#, expect![[r#" - // AstId: 1 + // AstId: Struct[0A3A, 0] pub(self) struct Unit; #[derive(Debug)] - // AstId: 2 - pub(self) struct Struct { - #[doc = " fld docs"] - pub(self) fld, - } + // AstId: Struct[B09D, 0] + pub(self) struct Struct { ... } - // AstId: 3 - pub(self) struct Tuple( - #[attr] - pub(self) 0, - ); + // AstId: Struct[466D, 0] + pub(self) struct Tuple(...); - // AstId: 4 - pub(self) union Ize { - pub(self) a, - pub(self) b, - } + // AstId: Union[F20E, 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[4082, 0] + pub(self) enum E { ... } "#]], ); } @@ -185,25 +162,19 @@ trait Tr: SuperTrait + 'lifetime { } "#, expect![[r#" - // AstId: 1 + // AstId: Static[5832, 0] pub static ST = _; - // AstId: 2 + // AstId: Const[EF58, 0] pub(self) const _ = _; #[attr] #[inner_attr_in_fn] - // AstId: 3 + // AstId: Fn[8E64, 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[9D45, 0] + pub(self) trait Tr { ... } "#]], ); } @@ -226,16 +197,16 @@ mod outline; expect![[r##" #[doc = " outer"] #[doc = " inner"] - // AstId: 1 + // AstId: Module[1128, 0] pub(self) mod inline { - // AstId: 3 + // AstId: Use[0000, 0] pub(self) use super::*; - // AstId: 4 + // AstId: Fn[7E05, 0] pub(self) fn fn_in_module; } - // AstId: 2 + // AstId: Module[22CE, 0] pub(self) mod outline; "##]], ); @@ -254,13 +225,13 @@ pub macro m2() {} m!(); "#, expect![[r#" - // AstId: 1 + // AstId: MacroRules[D26F, 0] macro_rules! m { ... } - // AstId: 2 + // AstId: MacroDef[B3AF, 0] pub macro m2 { ... } - // AstId: 3, SyntaxContextId: ROOT2024, ExpandTo: Items + // AstId: MacroCall[B356, 0], SyntaxContextId: ROOT2024, ExpandTo: Items m!(...); "#]], ); @@ -273,7 +244,7 @@ fn pub_self() { pub(self) struct S; "#, expect![[r#" - // AstId: 1 + // AstId: Struct[FF65, 0] pub(self) struct S; "#]], ) diff --git a/crates/hir-def/src/lang_item.rs b/crates/hir-def/src/lang_item.rs index 59344641f47a..768e05504da9 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 { 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 b41ff026bcaa..df22ac7093af 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 { +pub struct ItemLoc { pub container: ModuleId, - pub id: ItemTreeId, + pub id: AstId, } -impl Clone for ItemLoc { +impl Clone for ItemLoc { fn clone(&self) -> Self { *self } } -impl Copy for ItemLoc {} +impl Copy for ItemLoc {} -impl PartialEq for ItemLoc { +impl PartialEq for ItemLoc { fn eq(&self, other: &Self) -> bool { self.container == other.container && self.id == other.id } } -impl Eq for ItemLoc {} +impl Eq for ItemLoc {} -impl Hash for ItemLoc { +impl Hash for ItemLoc { fn hash(&self, state: &mut H) { self.container.hash(state); self.id.hash(state); } } +impl HasModule for ItemLoc { + #[inline] + fn module(&self, _db: &dyn DefDatabase) -> ModuleId { + self.container + } +} + #[derive(Debug)] -pub struct AssocItemLoc { +pub struct AssocItemLoc { pub container: ItemContainerId, - pub id: ItemTreeId, + pub id: AstId, } -impl Clone for AssocItemLoc { +impl Clone for AssocItemLoc { fn clone(&self) -> Self { *self } } -impl Copy for AssocItemLoc {} +impl Copy for AssocItemLoc {} -impl PartialEq for AssocItemLoc { +impl PartialEq for AssocItemLoc { fn eq(&self, other: &Self) -> bool { self.container == other.container && self.id == other.id } } -impl Eq for AssocItemLoc {} +impl Eq for AssocItemLoc {} -impl Hash for AssocItemLoc { +impl Hash for AssocItemLoc { fn hash(&self, state: &mut H) { self.container.hash(state); self.id.hash(state); } } -pub trait ItemTreeLoc { +impl HasModule for AssocItemLoc { + #[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; + type Ast: AstNode; + fn ast_id(&self) -> AstId; fn container(&self) -> Self::Container; } +impl AstIdLoc for ItemLoc { + type Container = ModuleId; + type Ast = N; + #[inline] + fn ast_id(&self) -> AstId { + self.id + } + #[inline] + fn container(&self) -> Self::Container { + self.container + } +} + +impl AstIdLoc for AssocItemLoc { + type Container = ItemContainerId; + type Ast = N; + #[inline] + fn ast_id(&self) -> AstId { + 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 { + type Ast = ast::$id_ty; + fn ast_id(&self) -> AstId { 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; +type FunctionLoc = AssocItemLoc; impl_intern!(FunctionId, FunctionLoc, intern_function, lookup_intern_function); -impl_loc!(FunctionLoc, id: Function, container: ItemContainerId); -type StructLoc = ItemLoc; +type StructLoc = ItemLoc; impl_intern!(StructId, StructLoc, intern_struct, lookup_intern_struct); -impl_loc!(StructLoc, id: Struct, container: ModuleId); -pub type UnionLoc = ItemLoc; +pub type UnionLoc = ItemLoc; impl_intern!(UnionId, UnionLoc, intern_union, lookup_intern_union); -impl_loc!(UnionLoc, id: Union, container: ModuleId); -pub type EnumLoc = ItemLoc; +pub type EnumLoc = ItemLoc; impl_intern!(EnumId, EnumLoc, intern_enum, lookup_intern_enum); -impl_loc!(EnumLoc, id: Enum, container: ModuleId); -type ConstLoc = AssocItemLoc; +type ConstLoc = AssocItemLoc; impl_intern!(ConstId, ConstLoc, intern_const, lookup_intern_const); -impl_loc!(ConstLoc, id: Const, container: ItemContainerId); -pub type StaticLoc = AssocItemLoc; +pub type StaticLoc = AssocItemLoc; impl_intern!(StaticId, StaticLoc, intern_static, lookup_intern_static); -impl_loc!(StaticLoc, id: Static, container: ItemContainerId); -pub type TraitLoc = ItemLoc; +pub type TraitLoc = ItemLoc; impl_intern!(TraitId, TraitLoc, intern_trait, lookup_intern_trait); -impl_loc!(TraitLoc, id: Trait, container: ModuleId); -pub type TraitAliasLoc = ItemLoc; +pub type TraitAliasLoc = ItemLoc; impl_intern!(TraitAliasId, TraitAliasLoc, intern_trait_alias, lookup_intern_trait_alias); -impl_loc!(TraitAliasLoc, id: TraitAlias, container: ModuleId); -type TypeAliasLoc = AssocItemLoc; +type TypeAliasLoc = AssocItemLoc; impl_intern!(TypeAliasId, TypeAliasLoc, intern_type_alias, lookup_intern_type_alias); -impl_loc!(TypeAliasLoc, id: TypeAlias, container: ItemContainerId); -type ImplLoc = ItemLoc; +type ImplLoc = ItemLoc; impl_intern!(ImplId, ImplLoc, intern_impl, lookup_intern_impl); -impl_loc!(ImplLoc, id: Impl, container: ModuleId); -type UseLoc = ItemLoc; +type UseLoc = ItemLoc; impl_intern!(UseId, UseLoc, intern_use, lookup_intern_use); -impl_loc!(UseLoc, id: Use, container: ModuleId); -type ExternCrateLoc = ItemLoc; +type ExternCrateLoc = ItemLoc; impl_intern!(ExternCrateId, ExternCrateLoc, intern_extern_crate, lookup_intern_extern_crate); -impl_loc!(ExternCrateLoc, id: ExternCrate, container: ModuleId); -type ExternBlockLoc = ItemLoc; +type ExternBlockLoc = ItemLoc; 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, + pub id: AstId, 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, + pub id: AstId, 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, + pub id: AstId, 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, + pub id: AstId, 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 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; @@ -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 HasModule for ItemId where - N: ItemTreeNode, + N: AstIdNode, ItemId: Lookup> + Copy, { #[inline] @@ -1003,7 +1046,7 @@ where #[inline] fn module_for_assoc_item_loc<'db>( db: &(dyn 'db + DefDatabase), - id: impl Lookup>, + id: impl Lookup>, ) -> 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 38fc4b3d118a..282809a7829a 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:1@58..64#14336# MyTraitMap2#0:2@31..42#ROOT2024# {#0:1@72..73#14336# - map#0:1@86..89#14336#:#0:1@89..90#14336# #0:1@89..90#14336#::#0:1@91..93#14336#std#0:1@93..96#14336#::#0:1@96..98#14336#collections#0:1@98..109#14336#::#0:1@109..111#14336#HashSet#0:1@111..118#14336#<#0:1@118..119#14336#(#0:1@119..120#14336#)#0:1@120..121#14336#>#0:1@121..122#14336#,#0:1@122..123#14336# -}#0:1@132..133#14336# +struct#0:MacroRules[A31F, 0]@58..64#14336# MyTraitMap2#0:MacroCall[DD57, 0]@31..42#ROOT2024# {#0:MacroRules[A31F, 0]@72..73#14336# + map#0:MacroRules[A31F, 0]@86..89#14336#:#0:MacroRules[A31F, 0]@89..90#14336# #0:MacroRules[A31F, 0]@89..90#14336#::#0:MacroRules[A31F, 0]@91..93#14336#std#0:MacroRules[A31F, 0]@93..96#14336#::#0:MacroRules[A31F, 0]@96..98#14336#collections#0:MacroRules[A31F, 0]@98..109#14336#::#0:MacroRules[A31F, 0]@109..111#14336#HashSet#0:MacroRules[A31F, 0]@111..118#14336#<#0:MacroRules[A31F, 0]@118..119#14336#(#0:MacroRules[A31F, 0]@119..120#14336#)#0:MacroRules[A31F, 0]@120..121#14336#>#0:MacroRules[A31F, 0]@121..122#14336#,#0:MacroRules[A31F, 0]@122..123#14336# +}#0:MacroRules[A31F, 0]@132..133#14336# "#]], ); } @@ -75,12 +75,12 @@ macro_rules! f { }; } -fn#0:2@30..32#ROOT2024# main#0:2@33..37#ROOT2024#(#0:2@37..38#ROOT2024#)#0:2@38..39#ROOT2024# {#0:2@40..41#ROOT2024# - 1#0:2@50..51#ROOT2024#;#0:2@51..52#ROOT2024# - 1.0#0:2@61..64#ROOT2024#;#0:2@64..65#ROOT2024# - (#0:2@74..75#ROOT2024#(#0:2@75..76#ROOT2024#1#0:2@76..77#ROOT2024#,#0:2@77..78#ROOT2024# )#0:2@78..79#ROOT2024#,#0:2@79..80#ROOT2024# )#0:2@80..81#ROOT2024#.#0:2@81..82#ROOT2024#0#0:2@82..85#ROOT2024#.#0:2@82..85#ROOT2024#0#0:2@82..85#ROOT2024#;#0:2@85..86#ROOT2024# - let#0:2@95..98#ROOT2024# x#0:2@99..100#ROOT2024# =#0:2@101..102#ROOT2024# 1#0:2@103..104#ROOT2024#;#0:2@104..105#ROOT2024# -}#0:2@110..111#ROOT2024# +fn#0:MacroCall[DD57, 0]@30..32#ROOT2024# main#0:MacroCall[DD57, 0]@33..37#ROOT2024#(#0:MacroCall[DD57, 0]@37..38#ROOT2024#)#0:MacroCall[DD57, 0]@38..39#ROOT2024# {#0:MacroCall[DD57, 0]@40..41#ROOT2024# + 1#0:MacroCall[DD57, 0]@50..51#ROOT2024#;#0:MacroCall[DD57, 0]@51..52#ROOT2024# + 1.0#0:MacroCall[DD57, 0]@61..64#ROOT2024#;#0:MacroCall[DD57, 0]@64..65#ROOT2024# + (#0:MacroCall[DD57, 0]@74..75#ROOT2024#(#0:MacroCall[DD57, 0]@75..76#ROOT2024#1#0:MacroCall[DD57, 0]@76..77#ROOT2024#,#0:MacroCall[DD57, 0]@77..78#ROOT2024# )#0:MacroCall[DD57, 0]@78..79#ROOT2024#,#0:MacroCall[DD57, 0]@79..80#ROOT2024# )#0:MacroCall[DD57, 0]@80..81#ROOT2024#.#0:MacroCall[DD57, 0]@81..82#ROOT2024#0#0:MacroCall[DD57, 0]@82..85#ROOT2024#.#0:MacroCall[DD57, 0]@82..85#ROOT2024#0#0:MacroCall[DD57, 0]@82..85#ROOT2024#;#0:MacroCall[DD57, 0]@85..86#ROOT2024# + let#0:MacroCall[DD57, 0]@95..98#ROOT2024# x#0:MacroCall[DD57, 0]@99..100#ROOT2024# =#0:MacroCall[DD57, 0]@101..102#ROOT2024# 1#0:MacroCall[DD57, 0]@103..104#ROOT2024#;#0:MacroCall[DD57, 0]@104..105#ROOT2024# +}#0:MacroCall[DD57, 0]@110..111#ROOT2024# "#]], @@ -171,7 +171,7 @@ fn main(foo: ()) { } fn main(foo: ()) { - /* error: unresolved macro unresolved */"helloworld!"#0:3@236..321#ROOT2024#; + /* error: unresolved macro unresolved */"helloworld!"#0:Fn[4154, 0]@236..321#ROOT2024#; } } @@ -197,7 +197,7 @@ macro_rules! mk_struct { #[macro_use] mod foo; -struct#1:1@59..65#14336# Foo#0:2@32..35#ROOT2024#(#1:1@70..71#14336#u32#0:2@41..44#ROOT2024#)#1:1@74..75#14336#;#1:1@75..76#14336# +struct#1:MacroRules[19BE, 0]@59..65#14336# Foo#0:MacroCall[FAA5, 0]@32..35#ROOT2024#(#1:MacroRules[19BE, 0]@70..71#14336#u32#0:MacroCall[FAA5, 0]@41..44#ROOT2024#)#1:MacroRules[19BE, 0]@74..75#14336#;#1:MacroRules[19BE, 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 b2e1adc3650d..8d29a5001822 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:1@45..47#ROOT2024# foo#0:1@48..51#ROOT2024#(#0:1@51..52#ROOT2024#�:1@52..53#ROOT2024#self#0:1@53..57#ROOT2024# )#0:1@57..58#ROOT2024# {#0:1@59..60#ROOT2024# - self#0:1@65..69#ROOT2024# .#0:1@69..70#ROOT2024#0#0:1@70..71#ROOT2024#.#0:1@71..72#ROOT2024#1#0:1@73..74#ROOT2024#;#0:1@74..75#ROOT2024# -}#0:1@76..77#ROOT2024#"#]], +fn#0:Fn[FA66, 0]@45..47#ROOT2024# foo#0:Fn[FA66, 0]@48..51#ROOT2024#(#0:Fn[FA66, 0]@51..52#ROOT2024#�:Fn[FA66, 0]@52..53#ROOT2024#self#0:Fn[FA66, 0]@53..57#ROOT2024# )#0:Fn[FA66, 0]@57..58#ROOT2024# {#0:Fn[FA66, 0]@59..60#ROOT2024# + self#0:Fn[FA66, 0]@65..69#ROOT2024# .#0:Fn[FA66, 0]@69..70#ROOT2024#0#0:Fn[FA66, 0]@70..71#ROOT2024#.#0:Fn[FA66, 0]@71..72#ROOT2024#1#0:Fn[FA66, 0]@73..74#ROOT2024#;#0:Fn[FA66, 0]@74..75#ROOT2024# +}#0:Fn[FA66, 0]@76..77#ROOT2024#"#]], ); } diff --git a/crates/hir-def/src/nameres.rs b/crates/hir-def/src/nameres.rs index d4b30a1d3e68..71da013102ed 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)>, - // 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, 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, diff --git a/crates/hir-def/src/nameres/assoc.rs b/crates/hir-def/src/nameres/assoc.rs index d45709b8b903..63fdbf6c19d8 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, MacroCallId)>>>, + // `ThinVec` as the vec is usually empty anyways + pub macro_calls: ThinVec<(AstId, MacroCallId)>, } impl TraitItems { @@ -35,12 +48,12 @@ impl TraitItems { db: &dyn DefDatabase, tr: TraitId, ) -> (Arc, 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 attribute_calls(&self) -> impl Iterator, 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, MacroCallId)>>>, + // `ThinVec` as the vec is usually empty anyways + pub macro_calls: ThinVec<(AstId, MacroCallId)>, } impl ImplItems { @@ -99,18 +111,18 @@ impl ImplItems { id: ImplId, ) -> (Arc, 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 attribute_calls(&self) -> impl Iterator, 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, + span_map: SpanMap, + cfg_options: &'a CfgOptions, + file_id: HirFileId, diagnostics: Vec, container: ItemContainerId, depth: usize, items: Vec<(Name, AssocItemId)>, - macro_calls: Vec<(AstId, MacroCallId)>, + macro_calls: ThinVec<(AstId, 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, MacroCallId)>>>, - Vec, - ) { - self.items.reserve(assoc_items.len()); - for &item in assoc_items { - self.collect_item(item_tree, tree_id, item); + item_list: Option, + ) -> (Box<[(Name, AssocItemId)]>, ThinVec<(AstId, MacroCallId)>, Vec) + { + 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 350c97c39825..34a129a88eaa 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, } #[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, - ast_id: AstId, - fn_id: FunctionId, - ) { + fn export_proc_macro(&mut self, def: ProcMacroDef, ast_id: AstId, 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, ) -> 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 de3d2f48367f..c495a0744919 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, candidates: Box<[String]> }, UnresolvedExternCrate { ast: AstId }, - UnresolvedImport { id: ItemTreeId, index: Idx }, - UnconfiguredCode { tree: TreeId, item: AttrOwner, cfg: CfgExpr, opts: CfgOptions }, + UnresolvedImport { id: AstId, index: Idx }, + UnconfiguredCode { ast_id: ErasedAstId, cfg: CfgExpr, opts: CfgOptions }, UnresolvedMacroCall { ast: MacroCallKind, path: ModPath }, UnimplementedBuiltinMacro { ast: AstId }, InvalidDeriveTarget { ast: AstId, id: usize }, @@ -28,7 +24,7 @@ pub enum DefDiagnosticKind { } #[derive(Clone, Debug, PartialEq, Eq)] -pub struct DefDiagnostics(Option>>); +pub struct DefDiagnostics(Option>); impl DefDiagnostics { pub fn new(diagnostics: Vec) -> 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 { - 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, + id: AstId, index: Idx, ) -> 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 74ce33a6419e..e0e32a777356 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 16988ddf04b2..491b6204bce2 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, - >, + lookup: impl Lookup>, ) -> Resolver<'_> { lookup.lookup(db).container().resolver(db) } diff --git a/crates/hir-def/src/signatures.rs b/crates/hir-def/src/signatures.rs index 44cfd72c48f5..b7d29f54d08e 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) -> 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, Arc) { 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, Arc) { 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, Arc) { 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, Arc) { 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, Arc) { 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, Arc) { 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, Arc) { 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, Arc) { 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, Arc) { 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))>>, - override_visibility: Option, + fields: InFile>, + override_visibility: Option, +) -> (Arena, 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::RecordField)>()), + |_, _| Name::missing(), + None, + ), + } +} + +fn lower_fields( + db: &dyn DefDatabase, + module: ModuleId, + fields: InFile, Field)>>, + mut field_name: impl FnMut(usize, &Field) -> Name, + override_visibility: Option, ) -> (Arena, 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, Option>>) { 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 { - 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 { + 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 { + 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 3867f39b8b17..aa373a27b0d5 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 HasSource for T where - T: ItemTreeLoc, - T::Id: ItemTreeNode, + T: AstIdLoc, { - type Value = ::Source; + type Value = T::Ast; fn ast_ptr(&self, db: &dyn DefDatabase) -> InFile> { - 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 { fn child_source(&self, db: &dyn DefDatabase) -> InFile>; } +/// 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, + index: Idx, +) -> 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) -> Arena { + // 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> for UseId { type Value = ast::UseTree; fn child_source( &self, db: &dyn DefDatabase, ) -> InFile, 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 for VariantId { type Value = Either; fn child_source(&self, db: &dyn DefDatabase) -> InFile> { - 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 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 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 3c67ee9fe5b3..8d10770b6a0e 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,62 @@ 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>, +) -> 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, container: ItemContainerId) -> Option { + match container { + ItemContainerId::TraitId(trait_) => Some(db.trait_visibility(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]) - } + trait_item_visibility(db, loc.container).unwrap_or_else(|| { + let resolver = def.resolver(db); + 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]) - } + trait_item_visibility(db, loc.container).unwrap_or_else(|| { + let resolver = def.resolver(db); + 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]) - } + trait_item_visibility(db, loc.container).unwrap_or_else(|| { + let resolver = def.resolver(db); + 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_query(db: &dyn DefDatabase, def: TraitId) -> Visibility { + let resolver = def.resolver(db); + 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 62b7b638e7b6..d5874f829ba5 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:0@0..0#ROOT2024 937550:0@0..0#ROOT2024 - IDENT hello 937550:0@0..0#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 7cb1b6c02075..39bc6e7dbd01 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>; #[salsa::invoke(ast_id_map)] + #[salsa::lru(512)] fn ast_id_map(&self, file_id: HirFileId) -> Arc; #[salsa::transparent] diff --git a/crates/hir-expand/src/files.rs b/crates/hir-expand/src/files.rs index 321ee8feb9a8..2a55bbcf843b 100644 --- a/crates/hir-expand/src/files.rs +++ b/crates/hir-expand/src/files.rs @@ -63,7 +63,7 @@ impl FileRange { /// It is stable across reparses, and can be used as salsa key/value. pub type AstId = crate::InFile>; -impl AstId { +impl AstId { pub fn to_node(&self, db: &dyn ExpandDatabase) -> N { self.to_ptr(db).to_node(&db.parse_or_expand(self.file_id)) } @@ -79,6 +79,13 @@ impl AstId { pub fn erase(&self) -> ErasedAstId { crate::InFile::new(self.file_id, self.value.erase()) } + #[inline] + pub fn upcast(self) -> AstId + where + N: Into, + { + self.map(|it| it.upcast()) + } } pub type ErasedAstId = crate::InFile; diff --git a/crates/hir-ty/src/chalk_db.rs b/crates/hir-ty/src/chalk_db.rs index cd799c03ddf7..398d82bf45ff 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 099100a73288..fae129fddbfe 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 785277d70c64..af4357c9f75f 100644 --- a/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs +++ b/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs @@ -458,7 +458,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, subst, cx.module); let visibility = if is_uninhabited { diff --git a/crates/hir-ty/src/drop.rs b/crates/hir-ty/src/drop.rs index 70763759ef0e..b9b0f9828661 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 { 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 3a020bf050d6..a886c33d157b 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::, _>>()?; (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 21e5428520e2..8fb8d64779bd 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 7cf948b178e4..e60cb4158ac7 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 7fcc89e5183a..3a2609429234 100644 --- a/crates/hir-ty/src/mir/lower.rs +++ b/crates/hir-ty/src/mir/lower.rs @@ -1920,11 +1920,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 7ae6e907e7ad..91dc2627d184 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 2b75bd6f1604..48af7b2e32a2 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/utils.rs b/crates/hir-ty/src/utils.rs index 1e0ff423ded6..f797e60b05e7 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 d6b43aeed4d0..62478d4fd86c 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 3a91050d15fa..8dc8e0fbdc13 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(), @@ -857,7 +857,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, } @@ -1044,73 +1044,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); @@ -1446,12 +1398,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())) } } @@ -1504,12 +1452,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())) } } @@ -1528,7 +1472,7 @@ impl Enum { } pub fn variants(self, db: &dyn HirDatabase) -> Vec { - 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 { @@ -1597,12 +1541,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())) } } @@ -2676,10 +2616,9 @@ impl ExternCrateDecl { pub fn resolved_crate(self, db: &dyn HirDatabase) -> Option { 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| { @@ -2690,25 +2629,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 { 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 { - 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)), } } } @@ -2716,12 +2659,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())) } } @@ -2841,12 +2780,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())) } } @@ -2935,11 +2870,7 @@ impl Trait { } fn all_macro_calls(&self, db: &dyn HirDatabase) -> Box<[(AstId, 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. @@ -2951,12 +2882,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())) } } @@ -2978,12 +2905,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())) } } @@ -3131,25 +3054,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()), } } } @@ -3246,12 +3167,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, @@ -3405,7 +3322,7 @@ fn as_assoc_item<'db, ID, DEF, LOC>( where ID: Lookup>, DEF: From, - LOC: ItemTreeNode, + LOC: AstIdNode, { match id.lookup(db).container { ItemContainerId::TraitId(_) | ItemContainerId::ImplId(_) => Some(ctor(DEF::from(id))), @@ -3421,7 +3338,7 @@ fn as_extern_assoc_item<'db, ID, DEF, LOC>( where ID: Lookup>, DEF: From, - LOC: ItemTreeNode, + LOC: AstIdNode, { match id.lookup(db).container { ItemContainerId::ExternBlockId(_) => Some(ctor(DEF::from(id))), @@ -4513,11 +4430,7 @@ impl Impl { } fn all_macro_calls(&self, db: &dyn HirDatabase) -> Box<[(AstId, 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() } } @@ -6425,3 +6338,7 @@ pub fn resolve_absolute_path<'a, I: Iterator + Clone + 'a>( }) .flatten() } + +fn as_name_opt(name: Option) -> 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 9393d08ad3f9..204c7cb4f7ac 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, @@ -18,7 +19,6 @@ use hir_def::{ keys::{self, Key}, }, item_scope::ItemScope, - item_tree::ItemTreeNode, nameres::DefMap, src::{HasChildSource, HasSource}, }; @@ -91,7 +91,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); } } @@ -175,16 +175,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); }); } } @@ -252,15 +250,14 @@ fn insert_item_loc( res: &mut DynMap, file_id: HirFileId, id: ID, - key: Key, + key: Key, ) where ID: Lookup + 'static, - Data: ItemTreeLoc, - N: ItemTreeNode, - N::Source: 'static, + Data: AstIdLoc, + 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 3369dfff2816..1eae3c296e08 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, @@ -109,8 +111,8 @@ fn unbalanced_brace() { "#, r#""#, expect![[r#" - SUBTREE $$ 1:0@0..0#ROOT2024 1:0@0..0#ROOT2024 - SUBTREE {} 0:0@9..10#ROOT2024 0:0@11..12#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 {}"#]], ); @@ -132,25 +134,25 @@ fn token_mapping_smoke_test() { struct MyTraitMap2 "#, expect![[r#" - SUBTREE $$ 1:0@0..20#ROOT2024 1:0@0..20#ROOT2024 - IDENT struct 0:0@34..40#ROOT2024 - IDENT MyTraitMap2 1:0@8..19#ROOT2024 - SUBTREE {} 0:0@48..49#ROOT2024 0:0@100..101#ROOT2024 - IDENT map 0:0@58..61#ROOT2024 - PUNCH : [alone] 0:0@61..62#ROOT2024 - PUNCH : [joint] 0:0@63..64#ROOT2024 - PUNCH : [alone] 0:0@64..65#ROOT2024 - IDENT std 0:0@65..68#ROOT2024 - PUNCH : [joint] 0:0@68..69#ROOT2024 - PUNCH : [alone] 0:0@69..70#ROOT2024 - IDENT collections 0:0@70..81#ROOT2024 - PUNCH : [joint] 0:0@81..82#ROOT2024 - PUNCH : [alone] 0:0@82..83#ROOT2024 - IDENT HashSet 0:0@83..90#ROOT2024 - PUNCH < [alone] 0:0@90..91#ROOT2024 - SUBTREE () 0:0@91..92#ROOT2024 0:0@92..93#ROOT2024 - PUNCH > [joint] 0:0@93..94#ROOT2024 - PUNCH , [alone] 0:0@94..95#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<()>, @@ -179,28 +181,28 @@ fn main() { } "#, expect![[r#" - SUBTREE $$ 1:0@0..63#ROOT2024 1:0@0..63#ROOT2024 - IDENT fn 1:0@1..3#ROOT2024 - IDENT main 1:0@4..8#ROOT2024 - SUBTREE () 1:0@8..9#ROOT2024 1:0@9..10#ROOT2024 - SUBTREE {} 1:0@11..12#ROOT2024 1:0@61..62#ROOT2024 - LITERAL Integer 1 1:0@17..18#ROOT2024 - PUNCH ; [alone] 1:0@18..19#ROOT2024 - LITERAL Float 1.0 1:0@24..27#ROOT2024 - PUNCH ; [alone] 1:0@27..28#ROOT2024 - SUBTREE () 1:0@33..34#ROOT2024 1:0@39..40#ROOT2024 - SUBTREE () 1:0@34..35#ROOT2024 1:0@37..38#ROOT2024 - LITERAL Integer 1 1:0@35..36#ROOT2024 - PUNCH , [alone] 1:0@36..37#ROOT2024 - PUNCH , [alone] 1:0@38..39#ROOT2024 - PUNCH . [alone] 1:0@40..41#ROOT2024 - LITERAL Float 0.0 1:0@41..44#ROOT2024 - PUNCH ; [alone] 1:0@44..45#ROOT2024 - IDENT let 1:0@50..53#ROOT2024 - IDENT x 1:0@54..55#ROOT2024 - PUNCH = [alone] 1:0@56..57#ROOT2024 - LITERAL Integer 1 1:0@58..59#ROOT2024 - PUNCH ; [alone] 1:0@59..60#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; @@ -226,14 +228,14 @@ fn expr_2021() { const { 1 }, "#, expect![[r#" - SUBTREE $$ 1:0@0..25#ROOT2024 1:0@0..25#ROOT2024 - IDENT _ 1:0@5..6#ROOT2024 - PUNCH ; [joint] 0:0@36..37#ROOT2024 - SUBTREE () 0:0@34..35#ROOT2024 0:0@34..35#ROOT2024 - IDENT const 1:0@12..17#ROOT2024 - SUBTREE {} 1:0@18..19#ROOT2024 1:0@22..23#ROOT2024 - LITERAL Integer 1 1:0@20..21#ROOT2024 - PUNCH ; [alone] 0:0@39..40#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 { @@ -254,13 +256,13 @@ fn expr_2021() { expect![[r#" ExpandError { inner: ( - 1:0@5..6#ROOT2024, + 1:Root[0000, 0]@5..6#ROOT2024, NoMatchingRule, ), } - SUBTREE $$ 1:0@0..8#ROOT2024 1:0@0..8#ROOT2024 - PUNCH ; [alone] 0:0@39..40#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 ;"#]], ); @@ -278,13 +280,13 @@ fn expr_2021() { expect![[r#" ExpandError { inner: ( - 1:0@5..10#ROOT2024, + 1:Root[0000, 0]@5..10#ROOT2024, NoMatchingRule, ), } - SUBTREE $$ 1:0@0..18#ROOT2024 1:0@0..18#ROOT2024 - PUNCH ; [alone] 0:0@39..40#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 ;"#]], ); @@ -304,26 +306,26 @@ fn expr_2021() { break 'foo bar, "#, expect![[r#" - SUBTREE $$ 1:0@0..76#ROOT2024 1:0@0..76#ROOT2024 - LITERAL Integer 4 1:0@5..6#ROOT2024 - PUNCH ; [joint] 0:0@41..42#ROOT2024 - LITERAL Str literal 1:0@12..21#ROOT2024 - PUNCH ; [joint] 0:0@41..42#ROOT2024 - SUBTREE () 0:0@39..40#ROOT2024 0:0@39..40#ROOT2024 - IDENT funcall 1:0@27..34#ROOT2024 - SUBTREE () 1:0@34..35#ROOT2024 1:0@35..36#ROOT2024 - PUNCH ; [joint] 0:0@41..42#ROOT2024 - SUBTREE () 0:0@39..40#ROOT2024 0:0@39..40#ROOT2024 - IDENT future 1:0@42..48#ROOT2024 - PUNCH . [alone] 1:0@48..49#ROOT2024 - IDENT await 1:0@49..54#ROOT2024 - PUNCH ; [joint] 0:0@41..42#ROOT2024 - SUBTREE () 0:0@39..40#ROOT2024 0:0@39..40#ROOT2024 - IDENT break 1:0@60..65#ROOT2024 - PUNCH ' [joint] 1:0@66..67#ROOT2024 - IDENT foo 1:0@67..70#ROOT2024 - IDENT bar 1:0@71..74#ROOT2024 - PUNCH ; [alone] 0:0@44..45#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"; @@ -345,13 +347,13 @@ fn expr_2021() { expect![[r#" ExpandError { inner: ( - 1:0@5..6#ROOT2024, + 1:Root[0000, 0]@5..6#ROOT2024, NoMatchingRule, ), } - SUBTREE $$ 1:0@0..8#ROOT2024 1:0@0..8#ROOT2024 - PUNCH ; [alone] 0:0@44..45#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 ;"#]], ); @@ -369,88 +371,88 @@ fn minus_belongs_to_literal() { check( "-1", expect![[r#" - SUBTREE $$ 1:0@0..2#ROOT2024 1:0@0..2#ROOT2024 - PUNCH - [alone] 0:0@10..11#ROOT2024 - LITERAL Integer 1 0:0@11..12#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:0@0..3#ROOT2024 1:0@0..3#ROOT2024 - PUNCH - [alone] 0:0@10..11#ROOT2024 - LITERAL Integer 1 0:0@11..12#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:0@0..2#ROOT2024 1:0@0..2#ROOT2024 - PUNCH - [alone] 0:0@25..26#ROOT2024 - LITERAL Integer 2 0:0@27..28#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:0@0..3#ROOT2024 1:0@0..3#ROOT2024 - PUNCH - [alone] 0:0@25..26#ROOT2024 - LITERAL Integer 2 0:0@27..28#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:0@0..4#ROOT2024 1:0@0..4#ROOT2024 - PUNCH - [alone] 0:0@43..44#ROOT2024 - LITERAL Float 3.0 0:0@45..48#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:0@0..5#ROOT2024 1:0@0..5#ROOT2024 - PUNCH - [alone] 0:0@43..44#ROOT2024 - LITERAL Float 3.0 0:0@45..48#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:0@0..2#ROOT2024 1:0@0..2#ROOT2024 - LITERAL Integer 1 1:0@1..2#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:0@0..3#ROOT2024 1:0@0..3#ROOT2024 - PUNCH - [alone] 1:0@1..2#ROOT2024 - LITERAL Integer 1 1:0@2..3#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:0@0..4#ROOT2024 1:0@0..4#ROOT2024 - LITERAL Float 1.0 1:0@1..4#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:0@0..5#ROOT2024 1:0@0..5#ROOT2024 - PUNCH - [alone] 1:0@1..2#ROOT2024 - LITERAL Float 1.0 1:0@2..5#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"#]], ); @@ -459,16 +461,16 @@ fn minus_belongs_to_literal() { expect![[r#" ExpandError { inner: ( - 1:0@1..2#ROOT2024, + 1:Root[0000, 0]@1..2#ROOT2024, BindingError( "expected literal", ), ), } - SUBTREE $$ 1:0@0..6#ROOT2024 1:0@0..6#ROOT2024 - PUNCH - [joint] 1:0@1..2#ROOT2024 - PUNCH - [alone] 1:0@2..3#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 55185aa492de..dc85592b4c82 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)] @@ -201,7 +202,9 @@ type ProtocolWrite = 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 fcea75ef672a..7d8a4a7bc52a 100644 --- a/crates/proc-macro-api/src/process.rs +++ b/crates/proc-macro-api/src/process.rs @@ -15,8 +15,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 +70,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; } 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 e0c6e68f8037..5aa1abb06c66 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 @@ -449,7 +449,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), }; @@ -491,7 +491,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 3a6ce639d135..5e0bc27e2420 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:2@0..100#ROOT2024 42:2@0..100#ROOT2024 - IDENT struct 42:2@0..6#ROOT2024 - IDENT S 42:2@7..8#ROOT2024 - PUNCH ; [alone] 42:2@8..9#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:2@0..100#ROOT2024 42:2@0..100#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:2@0..100#ROOT2024 42:2@0..100#ROOT2024 - IDENT struct 42:2@0..6#ROOT2024 - IDENT S 42:2@7..8#ROOT2024 - PUNCH ; [alone] 42:2@8..9#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:2@0..100#ROOT2024 42:2@0..100#ROOT2024 - IDENT compile_error 42:2@0..100#ROOT2024 - PUNCH ! [alone] 42:2@0..100#ROOT2024 - SUBTREE () 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024 - LITERAL Str #[derive(DeriveError)] struct S ; 42:2@0..100#ROOT2024 - PUNCH ; [alone] 42:2@0..100#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:2@0..100#ROOT2024 42:2@0..100#ROOT2024 - IDENT ident 42:2@0..5#ROOT2024 - PUNCH , [alone] 42:2@5..6#ROOT2024 - LITERAL Integer 0 42:2@7..8#ROOT2024 - PUNCH , [alone] 42:2@8..9#ROOT2024 - LITERAL Integer 1 42:2@10..11#ROOT2024 - PUNCH , [alone] 42:2@11..12#ROOT2024 - SUBTREE [] 42:2@13..14#ROOT2024 42:2@14..15#ROOT2024 - - - - SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024 - IDENT ident 42:2@0..5#ROOT2024 - PUNCH , [alone] 42:2@5..6#ROOT2024 - LITERAL Integer 0 42:2@7..8#ROOT2024 - PUNCH , [alone] 42:2@8..9#ROOT2024 - LITERAL Integer 1 42:2@10..11#ROOT2024 - PUNCH , [alone] 42:2@11..12#ROOT2024 - SUBTREE [] 42:2@13..14#ROOT2024 42:2@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 + + + + 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:2@0..100#ROOT2024 42:2@0..100#ROOT2024 - IDENT ident 42:2@0..5#ROOT2024 - PUNCH , [alone] 42:2@5..6#ROOT2024 - SUBTREE [] 42:2@7..8#ROOT2024 42:2@8..9#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:2@0..100#ROOT2024 42:2@0..100#ROOT2024 - IDENT ident 42:2@0..5#ROOT2024 - PUNCH , [alone] 42:2@5..6#ROOT2024 - SUBTREE [] 42:2@7..9#ROOT2024 42:2@7..9#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:2@0..100#ROOT2024 42:2@0..100#ROOT2024 - IDENT r#async 42:2@0..7#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:2@0..100#ROOT2024 42:2@0..100#ROOT2024 - IDENT r#async 42:2@0..7#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:2@0..100#ROOT2024 42:2@0..100#ROOT2024 - IDENT foo 42:2@0..3#ROOT2024 - IDENT bar 42:2@8..11#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:2@0..100#ROOT2024 42:2@0..100#ROOT2024 - IDENT r#joined 42:2@0..11#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:2@0..100#ROOT2024 42:2@0..100#ROOT2024 - IDENT set_def_site 42:2@0..12#ROOT2024 - IDENT resolved_at_def_site 42:2@13..33#ROOT2024 - IDENT start_span 42:2@34..44#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:2@0..100#ROOT2024 42:2@0..100#ROOT2024 - IDENT set_def_site 41:1@0..150#ROOT2024 - IDENT resolved_at_def_site 42:2@13..33#ROOT2024 - IDENT start_span 42:2@34..34#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"#]], ); } @@ -258,27 +258,27 @@ fn test_fn_like_mk_literals() { PUNCH - [alone] 1 LITERAL Integer 123 1"#]], expect![[r#" - SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024 - - - - SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024 - LITERAL ByteStr byte_string 42:2@0..100#ROOT2024 - LITERAL Char c 42:2@0..100#ROOT2024 - LITERAL Str string 42:2@0..100#ROOT2024 - LITERAL CStr cstring 42:2@0..100#ROOT2024 - LITERAL Float 3.14f64 42:2@0..100#ROOT2024 - PUNCH - [alone] 42:2@0..100#ROOT2024 - LITERAL Float 3.14f64 42:2@0..100#ROOT2024 - LITERAL Float 3.14 42:2@0..100#ROOT2024 - PUNCH - [alone] 42:2@0..100#ROOT2024 - LITERAL Float 3.14 42:2@0..100#ROOT2024 - LITERAL Integer 123i64 42:2@0..100#ROOT2024 - PUNCH - [alone] 42:2@0..100#ROOT2024 - LITERAL Integer 123i64 42:2@0..100#ROOT2024 - LITERAL Integer 123 42:2@0..100#ROOT2024 - PUNCH - [alone] 42:2@0..100#ROOT2024 - LITERAL Integer 123 42:2@0..100#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 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"#]], ); } @@ -296,13 +296,13 @@ fn test_fn_like_mk_idents() { IDENT standard 1 IDENT r#raw 1"#]], expect![[r#" - SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024 + SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024 - SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024 - IDENT standard 42:2@0..100#ROOT2024 - IDENT r#raw 42:2@0..100#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"#]], ); } @@ -358,51 +358,51 @@ fn test_fn_like_macro_clone_literals() { PUNCH , [alone] 1 LITERAL CStr null 1"#]], expect![[r#" - SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024 - LITERAL Integer 1u16 42:2@0..4#ROOT2024 - PUNCH , [alone] 42:2@4..5#ROOT2024 - LITERAL Integer 2_u32 42:2@6..11#ROOT2024 - PUNCH , [alone] 42:2@11..12#ROOT2024 - PUNCH - [alone] 42:2@13..14#ROOT2024 - LITERAL Integer 4i64 42:2@14..18#ROOT2024 - PUNCH , [alone] 42:2@18..19#ROOT2024 - LITERAL Float 3.14f32 42:2@20..27#ROOT2024 - PUNCH , [alone] 42:2@27..28#ROOT2024 - LITERAL Str hello bridge 42:2@29..43#ROOT2024 - PUNCH , [alone] 42:2@43..44#ROOT2024 - LITERAL Str suffixedsuffix 42:2@45..61#ROOT2024 - PUNCH , [alone] 42:2@61..62#ROOT2024 - LITERAL StrRaw(2) raw 42:2@63..73#ROOT2024 - PUNCH , [alone] 42:2@73..74#ROOT2024 - LITERAL Char a 42:2@75..78#ROOT2024 - PUNCH , [alone] 42:2@78..79#ROOT2024 - LITERAL Byte b 42:2@80..84#ROOT2024 - PUNCH , [alone] 42:2@84..85#ROOT2024 - LITERAL CStr null 42:2@86..93#ROOT2024 - - - - SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024 - LITERAL Integer 1u16 42:2@0..4#ROOT2024 - PUNCH , [alone] 42:2@4..5#ROOT2024 - LITERAL Integer 2_u32 42:2@6..11#ROOT2024 - PUNCH , [alone] 42:2@11..12#ROOT2024 - PUNCH - [alone] 42:2@13..14#ROOT2024 - LITERAL Integer 4i64 42:2@14..18#ROOT2024 - PUNCH , [alone] 42:2@18..19#ROOT2024 - LITERAL Float 3.14f32 42:2@20..27#ROOT2024 - PUNCH , [alone] 42:2@27..28#ROOT2024 - LITERAL Str hello bridge 42:2@29..43#ROOT2024 - PUNCH , [alone] 42:2@43..44#ROOT2024 - LITERAL Str suffixedsuffix 42:2@45..61#ROOT2024 - PUNCH , [alone] 42:2@61..62#ROOT2024 - LITERAL StrRaw(2) raw 42:2@63..73#ROOT2024 - PUNCH , [alone] 42:2@73..74#ROOT2024 - LITERAL Char a 42:2@75..78#ROOT2024 - PUNCH , [alone] 42:2@78..79#ROOT2024 - LITERAL Byte b 42:2@80..84#ROOT2024 - PUNCH , [alone] 42:2@84..85#ROOT2024 - LITERAL CStr null 42:2@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 + + + + 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"#]], ); } @@ -440,33 +440,33 @@ fn test_fn_like_macro_negative_literals() { PUNCH - [alone] 1 LITERAL Float 2.7 1"#]], expect![[r#" - SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024 - PUNCH - [alone] 42:2@0..1#ROOT2024 - LITERAL Integer 1u16 42:2@1..5#ROOT2024 - PUNCH , [alone] 42:2@5..6#ROOT2024 - PUNCH - [alone] 42:2@7..8#ROOT2024 - LITERAL Integer 2_u32 42:2@9..14#ROOT2024 - PUNCH , [alone] 42:2@14..15#ROOT2024 - PUNCH - [alone] 42:2@16..17#ROOT2024 - LITERAL Float 3.14f32 42:2@17..24#ROOT2024 - PUNCH , [alone] 42:2@24..25#ROOT2024 - PUNCH - [alone] 42:2@26..27#ROOT2024 - LITERAL Float 2.7 42:2@28..31#ROOT2024 - - - - SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024 - PUNCH - [alone] 42:2@0..1#ROOT2024 - LITERAL Integer 1u16 42:2@1..5#ROOT2024 - PUNCH , [alone] 42:2@5..6#ROOT2024 - PUNCH - [alone] 42:2@7..8#ROOT2024 - LITERAL Integer 2_u32 42:2@9..14#ROOT2024 - PUNCH , [alone] 42:2@14..15#ROOT2024 - PUNCH - [alone] 42:2@16..17#ROOT2024 - LITERAL Float 3.14f32 42:2@17..24#ROOT2024 - PUNCH , [alone] 42:2@24..25#ROOT2024 - PUNCH - [alone] 42:2@26..27#ROOT2024 - LITERAL Float 2.7 42:2@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 + + + + 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"#]], ); } @@ -496,21 +496,21 @@ fn test_attr_macro() { LITERAL Str #[attr_error(some arguments)] mod m {} 1 PUNCH ; [alone] 1"#]], expect![[r#" - SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024 - IDENT mod 42:2@0..3#ROOT2024 - IDENT m 42:2@4..5#ROOT2024 - SUBTREE {} 42:2@6..7#ROOT2024 42:2@7..8#ROOT2024 - - SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024 - IDENT some 42:2@0..4#ROOT2024 - IDENT arguments 42:2@5..14#ROOT2024 - - SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024 - IDENT compile_error 42:2@0..100#ROOT2024 - PUNCH ! [alone] 42:2@0..100#ROOT2024 - SUBTREE () 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024 - LITERAL Str #[attr_error(some arguments)] mod m {} 42:2@0..100#ROOT2024 - PUNCH ; [alone] 42:2@0..100#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 a0a45b269e4a..10af5662b5c0 100644 --- a/crates/proc-macro-srv/src/tests/utils.rs +++ b/crates/proc-macro-srv/src/tests/utils.rs @@ -1,7 +1,9 @@ //! utils used in proc-macro tests use expect_test::Expect; -use span::{EditionedFileId, ErasedFileAstId, FileId, Span, SpanAnchor, SyntaxContext, TokenId}; +use span::{ + EditionedFileId, FileId, ROOT_ERASED_FILE_AST_ID, Span, SpanAnchor, SyntaxContext, TokenId, +}; use tt::TextRange; use crate::{EnvSnapshot, ProcMacroSrv, dylib, proc_macro_test_dylib_path}; @@ -76,7 +78,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 +86,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), }; diff --git a/crates/span/Cargo.toml b/crates/span/Cargo.toml index b3b401c3db44..966962bab381 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 228fba1fa096..bd425714e0bd 100644 --- a/crates/span/src/ast_id.rs +++ b/crates/span/src/ast_id.rs @@ -4,137 +4,533 @@ //! 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)); + +/// 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 = + 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)); + +#[inline] +const fn u16_hash(hash: u64) -> u16 { + // We do basically the same as `FxHasher`. + const K: u16 = 0x72ed; + 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(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 { + // 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 { +pub struct FileAstId { raw: ErasedFileAstId, - covariant: PhantomData N>, + _marker: PhantomData N>, } -impl Clone for FileAstId { +/// Traits are manually implemented because `derive` adds redundant bounds. +impl Clone for FileAstId { + #[inline] fn clone(&self) -> FileAstId { *self } } -impl Copy for FileAstId {} +impl Copy for FileAstId {} -impl PartialEq for FileAstId { +impl PartialEq for FileAstId { fn eq(&self, other: &Self) -> bool { self.raw == other.raw } } -impl Eq for FileAstId {} -impl Hash for FileAstId { +impl Eq for FileAstId {} +impl Hash for FileAstId { fn hash(&self, hasher: &mut H) { self.raw.hash(hasher); } } -impl fmt::Debug for FileAstId { +impl fmt::Debug for FileAstId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "FileAstId::<{}>({})", type_name::(), self.raw) + write!(f, "FileAstId::<{}>({:?})", type_name::(), self.raw) } } -impl FileAstId { +impl FileAstId { // Can't make this a From implementation because of coherence + #[inline] pub fn upcast(self) -> FileAstId where N: Into, { - 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, + 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, +} + +impl AstIdNode for ast::ExternBlock {} + +fn extern_block_ast_id( + node: &SyntaxNode, + index_map: &mut ErasedAstIdNextIndexMap, +) -> Option { + 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 { + 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 { + if let Some(node) = ast::Impl::cast(node.clone()) { + let type_as_name = |ty: Option| 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 { + 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 { + 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 { + 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, - /// Reverse: map ptr to id. - map: hashbrown::HashTable>, + /// An arena of the ptrs and their associated ID. + arena: Arena<(SyntaxNodePtr, ErasedFileAstId)>, + /// Map ptr to id. + ptr_map: hashbrown::HashTable, + /// Map id to ptr. + id_map: hashbrown::HashTable, } +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() @@ -152,27 +548,108 @@ 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, false)); + } 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)) = + blocks.last_mut() + { + if !*already_allocated { + 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 = true; + } + } + + 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 +657,236 @@ impl AstIdMap { } } res.arena.shrink_to_fit(); - res + return res; + + fn parent_of(parent_idx: Option, 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))] + // FIXME: Seems redundant to store the root. + self.arena[Idx::from_raw(RawIdx::from_u32(0))].0 } pub fn ast_id(&self, item: &N) -> FileAstId { - 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> { + self.ast_id_for_ptr_for_block(AstPtr::new(block)) } pub fn ast_id_for_ptr(&self, ptr: AstPtr) -> FileAstId { 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, + ) -> Option> { + 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::>(), - ), - } + ) + }) } - pub fn get(&self, id: FileAstId) -> AstPtr { - 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 { + 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` always has + // a matching node). + pub fn get(&self, id: FileAstId) -> AstPtr { + 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::>(), - 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::::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::>(); + 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::>(); + 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 54f90908f367..1dec0d15447e 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; impl Span { @@ -60,7 +50,7 @@ impl fmt::Debug for SpanData { 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 cc7a886643a9..f58201793da2 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 b9ccd34cff06..10fda4804206 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 {