From 1a3feeebc420824d98362698a59c645914ada597 Mon Sep 17 00:00:00 2001 From: Vincent Esche Date: Fri, 6 Jun 2025 09:37:54 +0200 Subject: [PATCH 01/56] Make `Semantics<'db, dyn HirDatabase>` actually usable --- crates/hir/src/semantics.rs | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 4a2e8e379f..953e2e7a02 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -159,13 +159,13 @@ pub struct SemanticsImpl<'db> { macro_call_cache: RefCell, MacroCallId>>, } -impl fmt::Debug for Semantics<'_, DB> { +impl fmt::Debug for Semantics<'_, DB> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "Semantics {{ ... }}") } } -impl<'db, DB> ops::Deref for Semantics<'db, DB> { +impl<'db, DB: ?Sized> ops::Deref for Semantics<'db, DB> { type Target = SemanticsImpl<'db>; fn deref(&self) -> &Self::Target { @@ -173,12 +173,28 @@ impl<'db, DB> ops::Deref for Semantics<'db, DB> { } } +// Note: while this variant of `Semantics<'_, _>` might seem unused, as it does not +// find actual use within the rust-analyzer project itself, it exists to enable the use +// within e.g. tracked salsa functions in third-party crates that build upon `ra_ap_hir`. +impl Semantics<'_, dyn HirDatabase> { + /// Creates an instance that's weakly coupled to its underlying database type. + pub fn new_dyn(db: &'_ dyn HirDatabase) -> Semantics<'_, dyn HirDatabase> { + let impl_ = SemanticsImpl::new(db); + Semantics { db, imp: impl_ } + } +} + impl Semantics<'_, DB> { + /// Creates an instance that's strongly coupled to its underlying database type. pub fn new(db: &DB) -> Semantics<'_, DB> { let impl_ = SemanticsImpl::new(db); Semantics { db, imp: impl_ } } +} +// Note: We take `DB` as `?Sized` here in order to support type-erased +// use of `Semantics` via `Semantics<'_, dyn HirDatabase>`: +impl Semantics<'_, DB> { pub fn hir_file_for(&self, syntax_node: &SyntaxNode) -> HirFileId { self.imp.find_file(syntax_node).file_id } From cc508681484148dd6e25c2754c23af8517f87267 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Sun, 8 Jun 2025 01:07:55 +0300 Subject: [PATCH 02/56] Remove the optimization of builtin attrs in `is_inside_macro_call()` `#[cfg_attr]` is a builtin attr, but it may still contain a macro. --- crates/hir/src/semantics.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 4a2e8e379f..52a8012f40 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -25,7 +25,6 @@ use hir_expand::{ builtin::{BuiltinFnLikeExpander, EagerExpander}, db::ExpandDatabase, files::{FileRangeWrapper, HirFileRange, InRealFile}, - inert_attr_macro::find_builtin_attr_idx, mod_path::{ModPath, PathKind}, name::AsName, }; @@ -953,13 +952,6 @@ impl<'db> SemanticsImpl<'db> { let Some(item) = ast::Item::cast(ancestor) else { return false; }; - // Optimization to skip the semantic check. - if item.attrs().all(|attr| { - attr.simple_name() - .is_some_and(|attr| find_builtin_attr_idx(&Symbol::intern(&attr)).is_some()) - }) { - return false; - } self.with_ctx(|ctx| { if ctx.item_to_macro_call(token.with_value(&item)).is_some() { return true; From 7b64b407e8eb34aef52adedbec47434e4e27d8e8 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Sun, 8 Jun 2025 01:44:14 +0300 Subject: [PATCH 03/56] Correctly handle attr macros placed in cfg_attr in speculative expansion --- crates/hir-expand/src/db.rs | 46 +++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/crates/hir-expand/src/db.rs b/crates/hir-expand/src/db.rs index 7cb1b6c020..6fd9c497c1 100644 --- a/crates/hir-expand/src/db.rs +++ b/crates/hir-expand/src/db.rs @@ -13,7 +13,7 @@ use crate::{ AstId, BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerCallInfo, EagerExpander, EditionedFileId, ExpandError, ExpandResult, ExpandTo, HirFileId, MacroCallId, MacroCallKind, MacroCallLoc, MacroDefId, MacroDefKind, - attrs::{AttrId, collect_attrs}, + attrs::{AttrId, AttrInput, RawAttrs, collect_attrs}, builtin::pseudo_derive_attr_expansion, cfg_process, declarative::DeclarativeMacroExpander, @@ -241,30 +241,36 @@ pub fn expand_speculative( let attr_arg = match loc.kind { MacroCallKind::Attr { invoc_attr_index, .. } => { - let attr = if loc.def.is_attribute_derive() { + if loc.def.is_attribute_derive() { // for pseudo-derive expansion we actually pass the attribute itself only - ast::Attr::cast(speculative_args.clone()) + ast::Attr::cast(speculative_args.clone()).and_then(|attr| attr.token_tree()).map( + |token_tree| { + let mut tree = syntax_node_to_token_tree( + token_tree.syntax(), + span_map, + span, + DocCommentDesugarMode::ProcMacro, + ); + *tree.top_subtree_delimiter_mut() = tt::Delimiter::invisible_spanned(span); + tree + }, + ) } else { // Attributes may have an input token tree, build the subtree and map for this as well // then try finding a token id for our token if it is inside this input subtree. let item = ast::Item::cast(speculative_args.clone())?; - collect_attrs(&item) - .nth(invoc_attr_index.ast_index()) - .and_then(|x| Either::left(x.1)) - }?; - match attr.token_tree() { - Some(token_tree) => { - let mut tree = syntax_node_to_token_tree( - token_tree.syntax(), - span_map, - span, - DocCommentDesugarMode::ProcMacro, - ); - *tree.top_subtree_delimiter_mut() = tt::Delimiter::invisible_spanned(span); - - Some(tree) - } - _ => None, + let attrs = RawAttrs::new_expanded(db, &item, span_map, loc.krate.cfg_options(db)); + attrs.iter().find(|attr| attr.id == invoc_attr_index).and_then(|attr| { + match attr.input.as_deref()? { + AttrInput::TokenTree(tt) => { + let mut attr_arg = tt.clone(); + attr_arg.top_subtree_delimiter_mut().kind = + tt::DelimiterKind::Invisible; + Some(attr_arg) + } + AttrInput::Literal(_) => None, + } + }) } } _ => None, From 6f4a6d43490aa713590ffb76861c4bffd6b8f597 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Tue, 10 Jun 2025 14:04:21 +0300 Subject: [PATCH 04/56] Do not error at impls for unsized types that do not include `where Self: Sized` items --- crates/hir-ty/src/dyn_compatibility.rs | 2 +- crates/hir-ty/src/generics.rs | 2 +- crates/hir/src/lib.rs | 34 ++++++++++++++++++- .../handlers/trait_impl_missing_assoc_item.rs | 29 ++++++++++++++++ 4 files changed, 64 insertions(+), 3 deletions(-) diff --git a/crates/hir-ty/src/dyn_compatibility.rs b/crates/hir-ty/src/dyn_compatibility.rs index ed8d8dc262..48094945c1 100644 --- a/crates/hir-ty/src/dyn_compatibility.rs +++ b/crates/hir-ty/src/dyn_compatibility.rs @@ -122,7 +122,7 @@ pub fn dyn_compatibility_of_trait_query( res } -fn generics_require_sized_self(db: &dyn HirDatabase, def: GenericDefId) -> bool { +pub fn generics_require_sized_self(db: &dyn HirDatabase, def: GenericDefId) -> bool { let krate = def.module(db).krate(); let Some(sized) = LangItem::Sized.resolve_trait(db, krate) else { return false; diff --git a/crates/hir-ty/src/generics.rs b/crates/hir-ty/src/generics.rs index bb4aaf7889..a3ed39934c 100644 --- a/crates/hir-ty/src/generics.rs +++ b/crates/hir-ty/src/generics.rs @@ -229,7 +229,7 @@ impl Generics { } /// Returns a Substitution that replaces each parameter by itself (i.e. `Ty::Param`). - pub(crate) fn placeholder_subst(&self, db: &dyn HirDatabase) -> Substitution { + pub fn placeholder_subst(&self, db: &dyn HirDatabase) -> Substitution { Substitution::from_iter( Interner, self.iter_id().map(|id| match id { diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index e8218cf861..969fd3eb48 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -846,7 +846,7 @@ impl Module { ) } - let missing: Vec<_> = required_items + let mut missing: Vec<_> = required_items .filter(|(name, id)| { !impl_assoc_items_scratch.iter().any(|(impl_name, impl_item)| { discriminant(impl_item) == discriminant(id) && impl_name == name @@ -854,6 +854,38 @@ impl Module { }) .map(|(name, item)| (name.clone(), AssocItem::from(*item))) .collect(); + + if !missing.is_empty() { + let self_ty = db.impl_self_ty(impl_def.id).substitute( + Interner, + &hir_ty::generics::generics(db, impl_def.id.into()).placeholder_subst(db), + ); + let self_ty = if let TyKind::Alias(AliasTy::Projection(projection)) = + self_ty.kind(Interner) + { + db.normalize_projection( + projection.clone(), + db.trait_environment(impl_def.id.into()), + ) + } else { + self_ty + }; + let self_ty_is_guaranteed_unsized = matches!( + self_ty.kind(Interner), + TyKind::Dyn(..) | TyKind::Slice(..) | TyKind::Str + ); + if self_ty_is_guaranteed_unsized { + missing.retain(|(_, assoc_item)| { + let assoc_item = match *assoc_item { + AssocItem::Function(it) => it.id.into(), + AssocItem::Const(it) => it.id.into(), + AssocItem::TypeAlias(it) => it.id.into(), + }; + !hir_ty::dyn_compatibility::generics_require_sized_self(db, assoc_item) + }); + } + } + if !missing.is_empty() { acc.push( TraitImplMissingAssocItems { diff --git a/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs b/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs index fa7ba90a75..0e18ce9674 100644 --- a/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs +++ b/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs @@ -127,4 +127,33 @@ impl !Trait for () {} "#, ) } + + #[test] + fn impl_sized_for_unsized() { + check_diagnostics( + r#" +//- minicore: sized +trait Trait { + type Item + where + Self: Sized; + + fn item() + where + Self: Sized; +} + +trait OtherTrait {} + +impl Trait for () { + type Item = (); + fn item() {} +} + +// Items with Self: Sized bound not required to be implemented for unsized types. +impl Trait for str {} +impl Trait for dyn OtherTrait {} + "#, + ) + } } From e7ae13368bd6c13ef91da2943c8a980c52170388 Mon Sep 17 00:00:00 2001 From: Wilfred Hughes Date: Tue, 10 Jun 2025 12:17:15 +0100 Subject: [PATCH 05/56] [minor] Fix typos --- crates/hir-def/src/lib.rs | 2 +- docs/book/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs index b41ff026bc..1e8859a9cc 100644 --- a/crates/hir-def/src/lib.rs +++ b/crates/hir-def/src/lib.rs @@ -1245,7 +1245,7 @@ pub struct SyntheticSyntax; // Crate authors can opt their type out of completions in some cases. // This is done with the `#[rust_analyzer::completions(...)]` attribute. // -// All completeable things support `#[rust_analyzer::completions(ignore_flyimport)]`, +// All completable things support `#[rust_analyzer::completions(ignore_flyimport)]`, // which causes the thing to get excluded from flyimport completion. It will still // be completed when in scope. This is analogous to the setting `rust-analyzer.completion.autoimport.exclude` // with `"type": "always"`. diff --git a/docs/book/README.md b/docs/book/README.md index 464ea02512..0a3161f3af 100644 --- a/docs/book/README.md +++ b/docs/book/README.md @@ -19,7 +19,7 @@ mdbook will rebuild the documentation as changes are made. ## Making updates -While not required, installing the mdbook binary can be helfpul in order to see the changes. +While not required, installing the mdbook binary can be helpful in order to see the changes. Start with the mdbook [User Guide](https://rust-lang.github.io/mdBook/guide/installation.html) to familiarize yourself with the tool. ## Generated documentation From 8ca5ad6bddb8d857ce12622b762e7979cc2ca56e Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Wed, 11 Jun 2025 01:03:35 +0300 Subject: [PATCH 06/56] Fix proc macro server handling of strings with minuses It used to decompose them thinking they were numbers. --- .../proc-macro-test/imp/src/lib.rs | 1 + crates/proc-macro-srv/src/server_impl.rs | 54 ++++++++----------- crates/proc-macro-srv/src/tests/mod.rs | 2 + 3 files changed, 26 insertions(+), 31 deletions(-) diff --git a/crates/proc-macro-srv/proc-macro-test/imp/src/lib.rs b/crates/proc-macro-srv/proc-macro-test/imp/src/lib.rs index 6820e4b335..2a72e50f91 100644 --- a/crates/proc-macro-srv/proc-macro-test/imp/src/lib.rs +++ b/crates/proc-macro-srv/proc-macro-test/imp/src/lib.rs @@ -31,6 +31,7 @@ pub fn fn_like_mk_literals(_args: TokenStream) -> TokenStream { TokenTree::from(Literal::byte_string(b"byte_string")), TokenTree::from(Literal::character('c')), TokenTree::from(Literal::string("string")), + TokenTree::from(Literal::string("-string")), TokenTree::from(Literal::c_string(c"cstring")), // as of 2022-07-21, there's no method on `Literal` to build a raw // string or a raw byte string diff --git a/crates/proc-macro-srv/src/server_impl.rs b/crates/proc-macro-srv/src/server_impl.rs index ad28599033..dd576f23ae 100644 --- a/crates/proc-macro-srv/src/server_impl.rs +++ b/crates/proc-macro-srv/src/server_impl.rs @@ -199,37 +199,29 @@ pub(super) fn from_token_tree( } bridge::TokenTree::Literal(literal) => { - let token_trees = - if let Some((_minus, symbol)) = literal.symbol.as_str().split_once('-') { - let punct = tt::Punct { - spacing: tt::Spacing::Alone, - span: literal.span, - char: '-' as char, - }; - let leaf: tt::Leaf = tt::Leaf::from(punct); - let minus_tree = tt::TokenTree::from(leaf); - - let literal = tt::Literal { - symbol: Symbol::intern(symbol), - suffix: literal.suffix, - span: literal.span, - kind: literal_kind_to_internal(literal.kind), - }; - let leaf: tt::Leaf = tt::Leaf::from(literal); - let tree = tt::TokenTree::from(leaf); - vec![minus_tree, tree] - } else { - let literal = tt::Literal { - symbol: literal.symbol, - suffix: literal.suffix, - span: literal.span, - kind: literal_kind_to_internal(literal.kind), - }; - - let leaf: tt::Leaf = tt::Leaf::from(literal); - let tree = tt::TokenTree::from(leaf); - vec![tree] - }; + let mut token_trees = Vec::new(); + let mut symbol = literal.symbol; + if matches!( + literal.kind, + proc_macro::bridge::LitKind::Integer | proc_macro::bridge::LitKind::Float + ) && symbol.as_str().starts_with('-') + { + token_trees.push(tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { + spacing: tt::Spacing::Alone, + span: literal.span, + char: '-' as char, + }))); + symbol = Symbol::intern(&symbol.as_str()[1..]); + } + let literal = tt::Literal { + symbol, + suffix: literal.suffix, + span: literal.span, + kind: literal_kind_to_internal(literal.kind), + }; + let leaf: tt::Leaf = tt::Leaf::from(literal); + let tree = tt::TokenTree::from(leaf); + token_trees.push(tree); TokenStream { token_trees } } diff --git a/crates/proc-macro-srv/src/tests/mod.rs b/crates/proc-macro-srv/src/tests/mod.rs index 3a6ce639d1..d1ea89d2dc 100644 --- a/crates/proc-macro-srv/src/tests/mod.rs +++ b/crates/proc-macro-srv/src/tests/mod.rs @@ -244,6 +244,7 @@ fn test_fn_like_mk_literals() { LITERAL ByteStr byte_string 1 LITERAL Char c 1 LITERAL Str string 1 + LITERAL Str -string 1 LITERAL CStr cstring 1 LITERAL Float 3.14f64 1 PUNCH - [alone] 1 @@ -266,6 +267,7 @@ fn test_fn_like_mk_literals() { 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 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 From 4cf958cfd4da6faebdc1d4567f743d2344415df2 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 10 Jun 2025 08:52:41 +0200 Subject: [PATCH 07/56] fix: Hide dyn inlay hints for incomplete `impl`s --- crates/ide/src/inlay_hints/implied_dyn_trait.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/crates/ide/src/inlay_hints/implied_dyn_trait.rs b/crates/ide/src/inlay_hints/implied_dyn_trait.rs index 32d130503a..cd01c07583 100644 --- a/crates/ide/src/inlay_hints/implied_dyn_trait.rs +++ b/crates/ide/src/inlay_hints/implied_dyn_trait.rs @@ -22,9 +22,14 @@ pub(super) fn hints( let parent = paren.as_ref().and_then(|it| it.parent()).unwrap_or(parent); if ast::TypeBound::can_cast(parent.kind()) || ast::TypeAnchor::can_cast(parent.kind()) - || ast::Impl::cast(parent) - .and_then(|it| it.trait_()) - .is_some_and(|it| it.syntax() == path.syntax()) + || ast::Impl::cast(parent).is_some_and(|it| { + it.trait_().map_or( + // only show it for impl type if the impl is not incomplete, otherwise we + // are likely typing a trait impl + it.assoc_item_list().is_none_or(|it| it.l_curly_token().is_none()), + |trait_| trait_.syntax() == path.syntax(), + ) + }) { return None; } @@ -85,6 +90,7 @@ impl T {} // ^ dyn impl T for (T) {} // ^^^ dyn +impl T "#, ); } From 210c71eac56b05079f2418c975570ef48a94960b Mon Sep 17 00:00:00 2001 From: David Barsky Date: Sun, 8 Jun 2025 13:17:56 -0400 Subject: [PATCH 08/56] hir-ty: test (the absence of) incremental trait solving --- crates/hir-ty/src/tests/incremental.rs | 88 +++++++++++++++++++++++++- 1 file changed, 87 insertions(+), 1 deletion(-) diff --git a/crates/hir-ty/src/tests/incremental.rs b/crates/hir-ty/src/tests/incremental.rs index e8e3812c69..6ac260ac76 100644 --- a/crates/hir-ty/src/tests/incremental.rs +++ b/crates/hir-ty/src/tests/incremental.rs @@ -1,5 +1,5 @@ use base_db::SourceDatabase; -use hir_def::ModuleDefId; +use hir_def::{DefWithBodyId, ModuleDefId}; use test_fixture::WithFixture; use crate::{db::HirDatabase, test_db::TestDB}; @@ -359,3 +359,89 @@ impl SomeStruct { assert_eq!(expected, actual); } } + +#[test] +fn add_struct_invalidates_trait_solve() { + let (mut db, file_id) = TestDB::with_single_file( + " +//- /main.rs crate:main +struct SomeStruct; + +trait Trait { + fn method(&self) -> T; +} +impl Trait for SomeStruct {} + +fn main() { + let s = SomeStruct; + s.method(); + s.$0 +}", + ); + + { + let events = db.log_executed(|| { + let module = db.module_for_file(file_id.file_id(&db)); + let crate_def_map = module.def_map(&db); + let mut defs: Vec = vec![]; + visit_module(&db, crate_def_map, module.local_id, &mut |it| { + let def = match it { + ModuleDefId::FunctionId(it) => it.into(), + ModuleDefId::EnumVariantId(it) => it.into(), + ModuleDefId::ConstId(it) => it.into(), + ModuleDefId::StaticId(it) => it.into(), + _ => return, + }; + defs.push(def); + }); + + for def in defs { + let _inference_result = db.infer(def); + } + }); + assert!(format!("{events:?}").contains("trait_solve_shim")) + } + + let new_text = " +//- /main.rs crate:main +struct AnotherStruct; + +struct SomeStruct; + +trait Trait { + fn method(&self) -> T; +} +impl Trait for SomeStruct {} + +fn main() { + let s = SomeStruct; + s.method(); + s.$0 +}"; + + db.set_file_text(file_id.file_id(&db), new_text); + + { + let events = db.log_executed(|| { + let module = db.module_for_file(file_id.file_id(&db)); + let crate_def_map = module.def_map(&db); + let mut defs: Vec = vec![]; + + visit_module(&db, crate_def_map, module.local_id, &mut |it| { + let def = match it { + ModuleDefId::FunctionId(it) => it.into(), + ModuleDefId::EnumVariantId(it) => it.into(), + ModuleDefId::ConstId(it) => it.into(), + ModuleDefId::StaticId(it) => it.into(), + _ => return, + }; + defs.push(def); + }); + + for def in defs { + let _inference_result = db.infer(def); + } + }); + assert!(format!("{events:?}").contains("trait_solve_shim")) + } +} From b5bec2d3d2cedd77a85a136bce7989008d22b304 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 11 Jun 2025 21:01:40 +0000 Subject: [PATCH 09/56] chore(deps-dev): bump brace-expansion in /editors/code Bumps [brace-expansion](https://github.com/juliangruber/brace-expansion) from 1.1.11 to 1.1.12. - [Release notes](https://github.com/juliangruber/brace-expansion/releases) - [Commits](https://github.com/juliangruber/brace-expansion/compare/1.1.11...v1.1.12) --- updated-dependencies: - dependency-name: brace-expansion dependency-version: 1.1.12 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- editors/code/package-lock.json | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/editors/code/package-lock.json b/editors/code/package-lock.json index ab431140c1..57d67a69b2 100644 --- a/editors/code/package-lock.json +++ b/editors/code/package-lock.json @@ -695,9 +695,9 @@ } }, "node_modules/@eslint/config-array/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, "license": "MIT", "dependencies": { @@ -756,9 +756,9 @@ } }, "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, "license": "MIT", "dependencies": { @@ -1407,9 +1407,9 @@ ] }, "node_modules/@vscode/vsce/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, "license": "MIT", "dependencies": { @@ -1599,9 +1599,9 @@ "license": "ISC" }, "node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" @@ -2981,9 +2981,9 @@ } }, "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, "license": "MIT", "dependencies": { From 4bcf03e28b0f469637964db3d4af4eb619e76cbb Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Wed, 21 May 2025 00:04:59 +0300 Subject: [PATCH 10/56] Use stable AST IDs Instead of simple numbering, we hash important bits, like the name of the item. This will allow for much better incrementality, e.g. when you add an item. Currently, this invalidates the IDs of all following items, which invalidates pretty much everything. --- crates/hir-def/src/expr_store/lower.rs | 22 +- crates/hir-def/src/item_tree/pretty.rs | 6 +- crates/hir-def/src/item_tree/tests.rs | 64 +- .../hir-def/src/macro_expansion_tests/mbe.rs | 22 +- .../src/macro_expansion_tests/proc_macros.rs | 6 +- crates/hir-expand/src/builtin/quote.rs | 4 +- crates/hir-expand/src/files.rs | 4 +- crates/mbe/src/tests.rs | 232 ++--- .../proc-macro-api/src/legacy_protocol/msg.rs | 13 +- crates/proc-macro-api/src/process.rs | 14 +- crates/proc-macro-srv-cli/src/main_loop.rs | 7 +- crates/proc-macro-srv/src/dylib.rs | 15 +- crates/proc-macro-srv/src/lib.rs | 32 +- crates/proc-macro-srv/src/proc_macros.rs | 8 +- .../src/server_impl/rust_analyzer_span.rs | 17 +- crates/proc-macro-srv/src/tests/mod.rs | 316 +++--- crates/proc-macro-srv/src/tests/utils.rs | 34 +- crates/span/Cargo.toml | 3 + crates/span/src/ast_id.rs | 911 +++++++++++++++--- crates/span/src/lib.rs | 24 +- crates/span/src/map.rs | 2 +- crates/syntax/src/ast/node_ext.rs | 10 + 22 files changed, 1220 insertions(+), 546 deletions(-) diff --git a/crates/hir-def/src/expr_store/lower.rs b/crates/hir-def/src/expr_store/lower.rs index 29871f5e04..b7a482a85d 100644 --- a/crates/hir-def/src/expr_store/lower.rs +++ b/crates/hir-def/src/expr_store/lower.rs @@ -2141,26 +2141,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)) { diff --git a/crates/hir-def/src/item_tree/pretty.rs b/crates/hir-def/src/item_tree/pretty.rs index 47c6eb1329..51172c0a1e 100644 --- a/crates/hir-def/src/item_tree/pretty.rs +++ b/crates/hir-def/src/item_tree/pretty.rs @@ -353,8 +353,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 +377,7 @@ impl Printer<'_> { } fn print_ast_id(&mut self, ast_id: ErasedFileAstId) { - wln!(self, "// AstId: {:?}", ast_id.into_raw()); + wln!(self, "// AstId: {ast_id:#?}"); } } diff --git a/crates/hir-def/src/item_tree/tests.rs b/crates/hir-def/src/item_tree/tests.rs index 824fbfa592..abfff283ef 100644 --- a/crates/hir-def/src/item_tree/tests.rs +++ b/crates/hir-def/src/item_tree/tests.rs @@ -35,23 +35,23 @@ use a::{c, d::{e}}; #![no_std] #![doc = " another file comment"] - // AstId: 1 + // AstId: ExternCrate[5A82, 0] pub(self) extern crate self as renamed; - // AstId: 2 + // AstId: ExternCrate[7E1C, 0] pub(super) extern crate bli; - // AstId: 3 + // AstId: Use[0000, 0] pub use crate::path::{nested, items as renamed, Trait as _}; - // AstId: 4 + // AstId: Use[0000, 1] pub(self) use globs::*; #[doc = " docs on import"] - // AstId: 5 + // AstId: Use[0000, 2] pub(self) use crate::{A, B}; - // AstId: 6 + // AstId: Use[0000, 3] pub(self) use a::{c, d::{e}}; "##]], ); @@ -75,18 +75,18 @@ extern "C" { "#, expect![[r##" #[on_extern_block] - // AstId: 1 + // AstId: ExternBlock[0000, 0] extern "C" { #[on_extern_type] - // AstId: 2 + // AstId: TypeAlias[9FDF, 0] pub(self) type ExType; #[on_extern_static] - // AstId: 3 + // AstId: Static[43C1, 0] pub(self) static EX_STATIC = _; #[on_extern_fn] - // AstId: 4 + // AstId: Fn[452D, 0] pub(self) fn ex_fn; } "##]], @@ -124,39 +124,39 @@ enum E { } "#, expect![[r#" - // AstId: 1 + // AstId: Struct[DFF3, 0] pub(self) struct Unit; #[derive(Debug)] - // AstId: 2 + // AstId: Struct[C7A1, 0] pub(self) struct Struct { #[doc = " fld docs"] pub(self) fld, } - // AstId: 3 + // AstId: Struct[DAC2, 0] pub(self) struct Tuple( #[attr] pub(self) 0, ); - // AstId: 4 + // AstId: Union[2DBB, 0] pub(self) union Ize { pub(self) a, pub(self) b, } - // AstId: 5 + // AstId: Enum[7FF8, 0] pub(self) enum E - // AstId: 6 + // AstId: Variant[C717, 0] #[doc = " comment on Unit"] Unit, - // AstId: 7 + // AstId: Variant[AEAB, 0] #[doc = " comment on Tuple"] Tuple( pub(self) 0, ), - // AstId: 8 + // AstId: Variant[4B1B, 0] Struct { #[doc = " comment on a: u8"] pub(self) a, @@ -185,23 +185,23 @@ trait Tr: SuperTrait + 'lifetime { } "#, expect![[r#" - // AstId: 1 + // AstId: Static[B393, 0] pub static ST = _; - // AstId: 2 + // AstId: Const[B309, 0] pub(self) const _ = _; #[attr] #[inner_attr_in_fn] - // AstId: 3 + // AstId: Fn[75E3, 0] pub(self) fn f; - // AstId: 4 + // AstId: Trait[2998, 0] pub(self) trait Tr { - // AstId: 6 + // AstId: TypeAlias[9F08, 0] pub(self) type Assoc; - // AstId: 7 + // AstId: Fn[6C0C, 0] pub(self) fn method; } "#]], @@ -226,16 +226,16 @@ mod outline; expect![[r##" #[doc = " outer"] #[doc = " inner"] - // AstId: 1 + // AstId: Module[CF93, 0] pub(self) mod inline { - // AstId: 3 + // AstId: Use[0000, 0] pub(self) use super::*; - // AstId: 4 + // AstId: Fn[1B26, 0] pub(self) fn fn_in_module; } - // AstId: 2 + // AstId: Module[8994, 0] pub(self) mod outline; "##]], ); @@ -254,13 +254,13 @@ pub macro m2() {} m!(); "#, expect![[r#" - // AstId: 1 + // AstId: MacroRules[88CE, 0] macro_rules! m { ... } - // AstId: 2 + // AstId: MacroDef[DC34, 0] pub macro m2 { ... } - // AstId: 3, SyntaxContextId: ROOT2024, ExpandTo: Items + // AstId: MacroCall[612F, 0], SyntaxContextId: ROOT2024, ExpandTo: Items m!(...); "#]], ); @@ -273,7 +273,7 @@ fn pub_self() { pub(self) struct S; "#, expect![[r#" - // AstId: 1 + // AstId: Struct[42E2, 0] pub(self) struct S; "#]], ) diff --git a/crates/hir-def/src/macro_expansion_tests/mbe.rs b/crates/hir-def/src/macro_expansion_tests/mbe.rs index 38fc4b3d11..eea50d16f5 100644 --- a/crates/hir-def/src/macro_expansion_tests/mbe.rs +++ b/crates/hir-def/src/macro_expansion_tests/mbe.rs @@ -35,9 +35,9 @@ macro_rules! f { }; } -struct#0: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[8C8E, 0]@58..64#14336# MyTraitMap2#0:MacroCall[D499, 0]@31..42#ROOT2024# {#0:MacroRules[8C8E, 0]@72..73#14336# + map#0:MacroRules[8C8E, 0]@86..89#14336#:#0:MacroRules[8C8E, 0]@89..90#14336# #0:MacroRules[8C8E, 0]@89..90#14336#::#0:MacroRules[8C8E, 0]@91..93#14336#std#0:MacroRules[8C8E, 0]@93..96#14336#::#0:MacroRules[8C8E, 0]@96..98#14336#collections#0:MacroRules[8C8E, 0]@98..109#14336#::#0:MacroRules[8C8E, 0]@109..111#14336#HashSet#0:MacroRules[8C8E, 0]@111..118#14336#<#0:MacroRules[8C8E, 0]@118..119#14336#(#0:MacroRules[8C8E, 0]@119..120#14336#)#0:MacroRules[8C8E, 0]@120..121#14336#>#0:MacroRules[8C8E, 0]@121..122#14336#,#0:MacroRules[8C8E, 0]@122..123#14336# +}#0:MacroRules[8C8E, 0]@132..133#14336# "#]], ); } @@ -75,12 +75,12 @@ macro_rules! f { }; } -fn#0: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[D499, 0]@30..32#ROOT2024# main#0:MacroCall[D499, 0]@33..37#ROOT2024#(#0:MacroCall[D499, 0]@37..38#ROOT2024#)#0:MacroCall[D499, 0]@38..39#ROOT2024# {#0:MacroCall[D499, 0]@40..41#ROOT2024# + 1#0:MacroCall[D499, 0]@50..51#ROOT2024#;#0:MacroCall[D499, 0]@51..52#ROOT2024# + 1.0#0:MacroCall[D499, 0]@61..64#ROOT2024#;#0:MacroCall[D499, 0]@64..65#ROOT2024# + (#0:MacroCall[D499, 0]@74..75#ROOT2024#(#0:MacroCall[D499, 0]@75..76#ROOT2024#1#0:MacroCall[D499, 0]@76..77#ROOT2024#,#0:MacroCall[D499, 0]@77..78#ROOT2024# )#0:MacroCall[D499, 0]@78..79#ROOT2024#,#0:MacroCall[D499, 0]@79..80#ROOT2024# )#0:MacroCall[D499, 0]@80..81#ROOT2024#.#0:MacroCall[D499, 0]@81..82#ROOT2024#0#0:MacroCall[D499, 0]@82..85#ROOT2024#.#0:MacroCall[D499, 0]@82..85#ROOT2024#0#0:MacroCall[D499, 0]@82..85#ROOT2024#;#0:MacroCall[D499, 0]@85..86#ROOT2024# + let#0:MacroCall[D499, 0]@95..98#ROOT2024# x#0:MacroCall[D499, 0]@99..100#ROOT2024# =#0:MacroCall[D499, 0]@101..102#ROOT2024# 1#0:MacroCall[D499, 0]@103..104#ROOT2024#;#0:MacroCall[D499, 0]@104..105#ROOT2024# +}#0:MacroCall[D499, 0]@110..111#ROOT2024# "#]], @@ -171,7 +171,7 @@ fn main(foo: ()) { } fn main(foo: ()) { - /* error: unresolved macro unresolved */"helloworld!"#0:3@236..321#ROOT2024#; + /* error: unresolved macro unresolved */"helloworld!"#0:Fn[B9C7, 0]@236..321#ROOT2024#; } } @@ -197,7 +197,7 @@ macro_rules! mk_struct { #[macro_use] mod foo; -struct#1: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[E572, 0]@59..65#14336# Foo#0:MacroCall[BDD3, 0]@32..35#ROOT2024#(#1:MacroRules[E572, 0]@70..71#14336#u32#0:MacroCall[BDD3, 0]@41..44#ROOT2024#)#1:MacroRules[E572, 0]@74..75#14336#;#1:MacroRules[E572, 0]@75..76#14336# "#]], ); } diff --git a/crates/hir-def/src/macro_expansion_tests/proc_macros.rs b/crates/hir-def/src/macro_expansion_tests/proc_macros.rs index b2e1adc365..d5ae6f8d88 100644 --- a/crates/hir-def/src/macro_expansion_tests/proc_macros.rs +++ b/crates/hir-def/src/macro_expansion_tests/proc_macros.rs @@ -181,9 +181,9 @@ fn foo(&self) { self.0. 1; } -fn#0: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[4D85, 0]@45..47#ROOT2024# foo#0:Fn[4D85, 0]@48..51#ROOT2024#(#0:Fn[4D85, 0]@51..52#ROOT2024#�:Fn[4D85, 0]@52..53#ROOT2024#self#0:Fn[4D85, 0]@53..57#ROOT2024# )#0:Fn[4D85, 0]@57..58#ROOT2024# {#0:Fn[4D85, 0]@59..60#ROOT2024# + self#0:Fn[4D85, 0]@65..69#ROOT2024# .#0:Fn[4D85, 0]@69..70#ROOT2024#0#0:Fn[4D85, 0]@70..71#ROOT2024#.#0:Fn[4D85, 0]@71..72#ROOT2024#1#0:Fn[4D85, 0]@73..74#ROOT2024#;#0:Fn[4D85, 0]@74..75#ROOT2024# +}#0:Fn[4D85, 0]@76..77#ROOT2024#"#]], ); } diff --git a/crates/hir-expand/src/builtin/quote.rs b/crates/hir-expand/src/builtin/quote.rs index 62b7b638e7..d5874f829b 100644 --- a/crates/hir-expand/src/builtin/quote.rs +++ b/crates/hir-expand/src/builtin/quote.rs @@ -277,8 +277,8 @@ mod tests { assert_eq!(quoted.to_string(), "hello"); let t = format!("{quoted:#?}"); expect![[r#" - SUBTREE $$ 937550: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/files.rs b/crates/hir-expand/src/files.rs index 8024823cbc..e8f6b82434 100644 --- a/crates/hir-expand/src/files.rs +++ b/crates/hir-expand/src/files.rs @@ -2,7 +2,7 @@ use std::borrow::Borrow; use either::Either; -use span::{AstIdNode, ErasedFileAstId, FileAstId, FileId, SyntaxContext}; +use span::{ErasedFileAstId, FileAstId, FileId, SyntaxContext}; use syntax::{AstNode, AstPtr, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange, TextSize}; use crate::{ @@ -106,7 +106,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)) } diff --git a/crates/mbe/src/tests.rs b/crates/mbe/src/tests.rs index 769455faac..56034516ef 100644 --- a/crates/mbe/src/tests.rs +++ b/crates/mbe/src/tests.rs @@ -3,7 +3,9 @@ // FIXME: Move more of the nameres independent tests from // crates\hir-def\src\macro_expansion_tests\mod.rs to this use expect_test::expect; -use span::{Edition, EditionedFileId, ErasedFileAstId, FileId, Span, SpanAnchor, SyntaxContext}; +use span::{ + Edition, EditionedFileId, FileId, ROOT_ERASED_FILE_AST_ID, Span, SpanAnchor, SyntaxContext, +}; use stdx::format_to; use tt::{TextRange, TextSize}; @@ -24,7 +26,7 @@ fn check_( def_edition, SpanAnchor { file_id: EditionedFileId::new(FileId::from_raw(0), def_edition), - ast_id: ErasedFileAstId::from_raw(0), + ast_id: ROOT_ERASED_FILE_AST_ID, }, SyntaxContext::root(Edition::CURRENT), decl, @@ -37,7 +39,7 @@ fn check_( }; let call_anchor = SpanAnchor { file_id: EditionedFileId::new(FileId::from_raw(1), call_edition), - ast_id: ErasedFileAstId::from_raw(0), + ast_id: ROOT_ERASED_FILE_AST_ID, }; let arg_tt = syntax_bridge::parse_to_token_tree( call_edition, @@ -110,8 +112,8 @@ fn unbalanced_brace() { "#, r#""#, expect![[r#" - SUBTREE $$ 1: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 {}"#]], ); @@ -133,25 +135,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<()>, @@ -180,28 +182,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; @@ -227,14 +229,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 { @@ -255,13 +257,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 ;"#]], ); @@ -279,13 +281,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 ;"#]], ); @@ -305,26 +307,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"; @@ -346,13 +348,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 ;"#]], ); @@ -370,88 +372,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"#]], ); @@ -460,16 +462,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 55185aa492..4e1526fe48 100644 --- a/crates/proc-macro-api/src/legacy_protocol/msg.rs +++ b/crates/proc-macro-api/src/legacy_protocol/msg.rs @@ -22,9 +22,10 @@ pub const HAS_GLOBAL_SPANS: u32 = 3; pub const RUST_ANALYZER_SPAN_SUPPORT: u32 = 4; /// Whether literals encode their kind as an additional u32 field and idents their rawness as a u32 field. pub const EXTENDED_LEAF_DATA: u32 = 5; +pub const HASHED_AST_ID: u32 = 6; /// Current API version of the proc-macro protocol. -pub const CURRENT_API_VERSION: u32 = EXTENDED_LEAF_DATA; +pub const CURRENT_API_VERSION: u32 = HASHED_AST_ID; /// Represents requests sent from the client to the proc-macro-srv. #[derive(Debug, Serialize, Deserialize)] @@ -54,7 +55,7 @@ pub enum SpanMode { Id, /// Rust Analyzer-specific span handling mode. - RustAnalyzer, + RustAnalyzer { fixup_ast_id: u32 }, } /// Represents responses sent from the proc-macro-srv to the client. @@ -201,7 +202,9 @@ type ProtocolWrite = for<'o, 'msg> fn(out: &'o mut W, msg: &'msg str) #[cfg(test)] mod tests { use intern::{Symbol, sym}; - use span::{Edition, ErasedFileAstId, Span, SpanAnchor, SyntaxContext, TextRange, TextSize}; + use span::{ + Edition, ROOT_ERASED_FILE_AST_ID, Span, SpanAnchor, SyntaxContext, TextRange, TextSize, + }; use tt::{ Delimiter, DelimiterKind, Ident, Leaf, Literal, Punct, Spacing, TopSubtree, TopSubtreeBuilder, @@ -215,7 +218,7 @@ mod tests { span::FileId::from_raw(0xe4e4e), span::Edition::CURRENT, ), - ast_id: ErasedFileAstId::from_raw(0), + ast_id: ROOT_ERASED_FILE_AST_ID, }; let mut builder = TopSubtreeBuilder::new(Delimiter { @@ -305,7 +308,7 @@ mod tests { #[test] fn test_proc_macro_rpc_works() { let tt = fixture_token_tree(); - for v in RUST_ANALYZER_SPAN_SUPPORT..=CURRENT_API_VERSION { + for v in HASHED_AST_ID..=CURRENT_API_VERSION { let mut span_data_table = Default::default(); let task = ExpandMacro { data: ExpandMacroData { diff --git a/crates/proc-macro-api/src/process.rs b/crates/proc-macro-api/src/process.rs index fcea75ef67..e3b0614546 100644 --- a/crates/proc-macro-api/src/process.rs +++ b/crates/proc-macro-api/src/process.rs @@ -8,6 +8,7 @@ use std::{ }; use paths::AbsPath; +use span::FIXUP_ERASED_FILE_AST_ID_MARKER; use stdx::JodChild; use crate::{ @@ -15,8 +16,7 @@ use crate::{ legacy_protocol::{ json::{read_json, write_json}, msg::{ - CURRENT_API_VERSION, Message, RUST_ANALYZER_SPAN_SUPPORT, Request, Response, - ServerConfig, SpanMode, + CURRENT_API_VERSION, HASHED_AST_ID, Message, Request, Response, ServerConfig, SpanMode, }, }, }; @@ -71,7 +71,9 @@ impl ProcMacroServerProcess { Ok(v) => { tracing::info!("Proc-macro server version: {v}"); srv.version = v; - if srv.version >= RUST_ANALYZER_SPAN_SUPPORT { + if srv.version >= HASHED_AST_ID { + // We don't enable spans on versions prior to `HASHED_AST_ID`, because their ast id layout + // is different. if let Ok(mode) = srv.enable_rust_analyzer_spans() { srv.mode = mode; } @@ -111,7 +113,11 @@ impl ProcMacroServerProcess { /// Enable support for rust-analyzer span mode if the server supports it. fn enable_rust_analyzer_spans(&self) -> Result { - let request = Request::SetConfig(ServerConfig { span_mode: SpanMode::RustAnalyzer }); + let request = Request::SetConfig(ServerConfig { + span_mode: SpanMode::RustAnalyzer { + fixup_ast_id: FIXUP_ERASED_FILE_AST_ID_MARKER.into_raw(), + }, + }); let response = self.send_task(request)?; match response { diff --git a/crates/proc-macro-srv-cli/src/main_loop.rs b/crates/proc-macro-srv-cli/src/main_loop.rs index f54dff1f2d..25a49fbff9 100644 --- a/crates/proc-macro-srv-cli/src/main_loop.rs +++ b/crates/proc-macro-srv-cli/src/main_loop.rs @@ -26,7 +26,7 @@ pub(crate) fn run() -> io::Result<()> { let write_response = |msg: msg::Response| msg.write(write_json, &mut io::stdout().lock()); let env = EnvSnapshot::default(); - let srv = proc_macro_srv::ProcMacroSrv::new(&env); + let mut srv = proc_macro_srv::ProcMacroSrv::new(&env); let mut span_mode = SpanMode::Id; @@ -78,7 +78,7 @@ pub(crate) fn run() -> io::Result<()> { }) .map_err(msg::PanicMessage) }), - SpanMode::RustAnalyzer => msg::Response::ExpandMacroExtended({ + SpanMode::RustAnalyzer { .. } => msg::Response::ExpandMacroExtended({ let mut span_data_table = deserialize_span_data_index_map(&span_data_table); let def_site = span_data_table[def_site]; @@ -122,6 +122,9 @@ pub(crate) fn run() -> io::Result<()> { msg::Request::ApiVersionCheck {} => msg::Response::ApiVersionCheck(CURRENT_API_VERSION), msg::Request::SetConfig(config) => { span_mode = config.span_mode; + if let SpanMode::RustAnalyzer { fixup_ast_id } = span_mode { + srv.set_fixup_ast_id(fixup_ast_id); + } msg::Response::SetConfig(config) } }; diff --git a/crates/proc-macro-srv/src/dylib.rs b/crates/proc-macro-srv/src/dylib.rs index c49159df99..c64a9833e3 100644 --- a/crates/proc-macro-srv/src/dylib.rs +++ b/crates/proc-macro-srv/src/dylib.rs @@ -3,6 +3,7 @@ mod version; use proc_macro::bridge; +use span::ErasedFileAstId; use std::{fmt, fs, io, time::SystemTime}; use libloading::Library; @@ -161,14 +162,20 @@ impl Expander { def_site: S, call_site: S, mixed_site: S, + fixup_ast_id: ErasedFileAstId, ) -> Result, String> where ::TokenStream: Default, { - let result = self - .inner - .proc_macros - .expand(macro_name, macro_body, attributes, def_site, call_site, mixed_site); + let result = self.inner.proc_macros.expand( + macro_name, + macro_body, + attributes, + def_site, + call_site, + mixed_site, + fixup_ast_id, + ); result.map_err(|e| e.into_string().unwrap_or_default()) } diff --git a/crates/proc-macro-srv/src/lib.rs b/crates/proc-macro-srv/src/lib.rs index 223c5a54b7..22afa018de 100644 --- a/crates/proc-macro-srv/src/lib.rs +++ b/crates/proc-macro-srv/src/lib.rs @@ -41,7 +41,7 @@ use std::{ }; use paths::{Utf8Path, Utf8PathBuf}; -use span::{Span, TokenId}; +use span::{ErasedFileAstId, FIXUP_ERASED_FILE_AST_ID_MARKER, Span, TokenId}; use crate::server_impl::TokenStream; @@ -57,11 +57,16 @@ pub const RUSTC_VERSION_STRING: &str = env!("RUSTC_VERSION"); pub struct ProcMacroSrv<'env> { expanders: Mutex>>, env: &'env EnvSnapshot, + fixup_ast_id: ErasedFileAstId, } impl<'env> ProcMacroSrv<'env> { pub fn new(env: &'env EnvSnapshot) -> Self { - Self { expanders: Default::default(), env } + Self { expanders: Default::default(), env, fixup_ast_id: FIXUP_ERASED_FILE_AST_ID_MARKER } + } + + pub fn set_fixup_ast_id(&mut self, fixup_ast_id: u32) { + self.fixup_ast_id = ErasedFileAstId::from_raw(fixup_ast_id); } } @@ -101,6 +106,7 @@ impl ProcMacroSrv<'_> { def_site, call_site, mixed_site, + self.fixup_ast_id, ) .map(|tt| tt.0) }); @@ -156,25 +162,41 @@ impl ProcMacroSrv<'_> { pub trait ProcMacroSrvSpan: Copy + Send { type Server: proc_macro::bridge::server::Server>; - fn make_server(call_site: Self, def_site: Self, mixed_site: Self) -> Self::Server; + fn make_server( + call_site: Self, + def_site: Self, + mixed_site: Self, + fixup_ast_id: ErasedFileAstId, + ) -> Self::Server; } impl ProcMacroSrvSpan for TokenId { type Server = server_impl::token_id::TokenIdServer; - fn make_server(call_site: Self, def_site: Self, mixed_site: Self) -> Self::Server { + fn make_server( + call_site: Self, + def_site: Self, + mixed_site: Self, + _fixup_ast_id: ErasedFileAstId, + ) -> Self::Server { Self::Server { call_site, def_site, mixed_site } } } impl ProcMacroSrvSpan for Span { type Server = server_impl::rust_analyzer_span::RaSpanServer; - fn make_server(call_site: Self, def_site: Self, mixed_site: Self) -> Self::Server { + fn make_server( + call_site: Self, + def_site: Self, + mixed_site: Self, + fixup_ast_id: ErasedFileAstId, + ) -> Self::Server { Self::Server { call_site, def_site, mixed_site, tracked_env_vars: Default::default(), tracked_paths: Default::default(), + fixup_ast_id, } } } diff --git a/crates/proc-macro-srv/src/proc_macros.rs b/crates/proc-macro-srv/src/proc_macros.rs index 18532706c4..3b9c45894c 100644 --- a/crates/proc-macro-srv/src/proc_macros.rs +++ b/crates/proc-macro-srv/src/proc_macros.rs @@ -1,6 +1,7 @@ //! Proc macro ABI use proc_macro::bridge; +use span::ErasedFileAstId; use crate::{ProcMacroKind, ProcMacroSrvSpan, server_impl::TopSubtree}; @@ -22,6 +23,7 @@ impl ProcMacros { def_site: S, call_site: S, mixed_site: S, + fixup_ast_id: ErasedFileAstId, ) -> Result, crate::PanicMessage> { let parsed_body = crate::server_impl::TokenStream::with_subtree(macro_body); @@ -37,7 +39,7 @@ impl ProcMacros { { let res = client.run( &bridge::server::SameThread, - S::make_server(call_site, def_site, mixed_site), + S::make_server(call_site, def_site, mixed_site, fixup_ast_id), parsed_body, cfg!(debug_assertions), ); @@ -48,7 +50,7 @@ impl ProcMacros { bridge::client::ProcMacro::Bang { name, client } if *name == macro_name => { let res = client.run( &bridge::server::SameThread, - S::make_server(call_site, def_site, mixed_site), + S::make_server(call_site, def_site, mixed_site, fixup_ast_id), parsed_body, cfg!(debug_assertions), ); @@ -59,7 +61,7 @@ impl ProcMacros { bridge::client::ProcMacro::Attr { name, client } if *name == macro_name => { let res = client.run( &bridge::server::SameThread, - S::make_server(call_site, def_site, mixed_site), + S::make_server(call_site, def_site, mixed_site, fixup_ast_id), parsed_attributes, parsed_body, cfg!(debug_assertions), diff --git a/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs b/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs index 5d1271ba81..b071ad80f5 100644 --- a/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs +++ b/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs @@ -11,7 +11,7 @@ use std::{ use intern::Symbol; use proc_macro::bridge::{self, server}; -use span::{FIXUP_ERASED_FILE_AST_ID_MARKER, Span}; +use span::{ErasedFileAstId, Span}; use tt::{TextRange, TextSize}; use crate::server_impl::{from_token_tree, literal_from_str, token_stream::TokenStreamBuilder}; @@ -28,6 +28,7 @@ pub struct RaSpanServer { pub call_site: Span, pub def_site: Span, pub mixed_site: Span, + pub fixup_ast_id: ErasedFileAstId, } impl server::Types for RaSpanServer { @@ -181,10 +182,10 @@ impl server::Span for RaSpanServer { fn join(&mut self, first: Self::Span, second: Self::Span) -> Option { // We can't modify the span range for fixup spans, those are meaningful to fixup, so just // prefer the non-fixup span. - if first.anchor.ast_id == FIXUP_ERASED_FILE_AST_ID_MARKER { + if first.anchor.ast_id == self.fixup_ast_id { return Some(second); } - if second.anchor.ast_id == FIXUP_ERASED_FILE_AST_ID_MARKER { + if second.anchor.ast_id == self.fixup_ast_id { return Some(first); } // FIXME: Once we can talk back to the client, implement a "long join" request for anchors @@ -213,7 +214,7 @@ impl server::Span for RaSpanServer { end: Bound, ) -> Option { // We can't modify the span range for fixup spans, those are meaningful to fixup. - if span.anchor.ast_id == FIXUP_ERASED_FILE_AST_ID_MARKER { + if span.anchor.ast_id == self.fixup_ast_id { return Some(span); } let length = span.range.len().into(); @@ -256,7 +257,7 @@ impl server::Span for RaSpanServer { fn end(&mut self, span: Self::Span) -> Self::Span { // We can't modify the span range for fixup spans, those are meaningful to fixup. - if span.anchor.ast_id == FIXUP_ERASED_FILE_AST_ID_MARKER { + if span.anchor.ast_id == self.fixup_ast_id { return span; } Span { range: TextRange::empty(span.range.end()), ..span } @@ -264,7 +265,7 @@ impl server::Span for RaSpanServer { fn start(&mut self, span: Self::Span) -> Self::Span { // We can't modify the span range for fixup spans, those are meaningful to fixup. - if span.anchor.ast_id == FIXUP_ERASED_FILE_AST_ID_MARKER { + if span.anchor.ast_id == self.fixup_ast_id { return span; } Span { range: TextRange::empty(span.range.start()), ..span } @@ -318,7 +319,7 @@ mod tests { range: TextRange::empty(TextSize::new(0)), anchor: span::SpanAnchor { file_id: EditionedFileId::current_edition(FileId::from_raw(0)), - ast_id: span::ErasedFileAstId::from_raw(0), + ast_id: span::ROOT_ERASED_FILE_AST_ID, }, ctx: SyntaxContext::root(span::Edition::CURRENT), }; @@ -360,7 +361,7 @@ mod tests { range: TextRange::empty(TextSize::new(0)), anchor: span::SpanAnchor { file_id: EditionedFileId::current_edition(FileId::from_raw(0)), - ast_id: span::ErasedFileAstId::from_raw(0), + ast_id: span::ROOT_ERASED_FILE_AST_ID, }, ctx: SyntaxContext::root(span::Edition::CURRENT), }; diff --git a/crates/proc-macro-srv/src/tests/mod.rs b/crates/proc-macro-srv/src/tests/mod.rs index d1ea89d2dc..08495f50bf 100644 --- a/crates/proc-macro-srv/src/tests/mod.rs +++ b/crates/proc-macro-srv/src/tests/mod.rs @@ -21,14 +21,14 @@ fn test_derive_empty() { SUBTREE $$ 1 1"#]], expect![[r#" - SUBTREE $$ 42: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: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: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"#]], ); } @@ -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"#]], ); } @@ -259,28 +259,28 @@ 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:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@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 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 + LITERAL ByteStr byte_string 42:Root[0000, 0]@0..100#ROOT2024 + LITERAL Char c 42:Root[0000, 0]@0..100#ROOT2024 + LITERAL Str string 42:Root[0000, 0]@0..100#ROOT2024 + LITERAL Str -string 42:Root[0000, 0]@0..100#ROOT2024 + LITERAL CStr cstring 42:Root[0000, 0]@0..100#ROOT2024 + LITERAL Float 3.14f64 42:Root[0000, 0]@0..100#ROOT2024 + PUNCH - [alone] 42:Root[0000, 0]@0..100#ROOT2024 + LITERAL Float 3.14f64 42:Root[0000, 0]@0..100#ROOT2024 + LITERAL Float 3.14 42:Root[0000, 0]@0..100#ROOT2024 + PUNCH - [alone] 42:Root[0000, 0]@0..100#ROOT2024 + LITERAL Float 3.14 42:Root[0000, 0]@0..100#ROOT2024 + LITERAL Integer 123i64 42:Root[0000, 0]@0..100#ROOT2024 + PUNCH - [alone] 42:Root[0000, 0]@0..100#ROOT2024 + LITERAL Integer 123i64 42:Root[0000, 0]@0..100#ROOT2024 + LITERAL Integer 123 42:Root[0000, 0]@0..100#ROOT2024 + PUNCH - [alone] 42:Root[0000, 0]@0..100#ROOT2024 + LITERAL Integer 123 42:Root[0000, 0]@0..100#ROOT2024"#]], ); } @@ -298,13 +298,13 @@ fn test_fn_like_mk_idents() { IDENT standard 1 IDENT r#raw 1"#]], expect![[r#" - SUBTREE $$ 42: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"#]], ); } @@ -360,51 +360,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: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: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"#]], ); } @@ -442,33 +442,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: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: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"#]], ); } @@ -498,21 +498,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: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: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: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: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 compile_error 42:Root[0000, 0]@0..100#ROOT2024 + PUNCH ! [alone] 42:Root[0000, 0]@0..100#ROOT2024 + SUBTREE () 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024 + LITERAL Str #[attr_error(some arguments)] mod m {} 42:Root[0000, 0]@0..100#ROOT2024 + PUNCH ; [alone] 42:Root[0000, 0]@0..100#ROOT2024"#]], ); } diff --git a/crates/proc-macro-srv/src/tests/utils.rs b/crates/proc-macro-srv/src/tests/utils.rs index a0a45b269e..e0a69608de 100644 --- a/crates/proc-macro-srv/src/tests/utils.rs +++ b/crates/proc-macro-srv/src/tests/utils.rs @@ -1,7 +1,10 @@ //! utils used in proc-macro tests use expect_test::Expect; -use span::{EditionedFileId, ErasedFileAstId, FileId, Span, SpanAnchor, SyntaxContext, TokenId}; +use span::{ + EditionedFileId, FIXUP_ERASED_FILE_AST_ID_MARKER, FileId, ROOT_ERASED_FILE_AST_ID, Span, + SpanAnchor, SyntaxContext, TokenId, +}; use tt::TextRange; use crate::{EnvSnapshot, ProcMacroSrv, dylib, proc_macro_test_dylib_path}; @@ -65,8 +68,17 @@ fn assert_expand_impl( let input_ts_string = format!("{input_ts:?}"); let attr_ts_string = attr_ts.as_ref().map(|it| format!("{it:?}")); - let res = - expander.expand(macro_name, input_ts, attr_ts, def_site, call_site, mixed_site).unwrap(); + let res = expander + .expand( + macro_name, + input_ts, + attr_ts, + def_site, + call_site, + mixed_site, + FIXUP_ERASED_FILE_AST_ID_MARKER, + ) + .unwrap(); expect.assert_eq(&format!( "{input_ts_string}\n\n{}\n\n{res:?}", attr_ts_string.unwrap_or_default() @@ -76,7 +88,7 @@ fn assert_expand_impl( range: TextRange::new(0.into(), 150.into()), anchor: SpanAnchor { file_id: EditionedFileId::current_edition(FileId::from_raw(41)), - ast_id: ErasedFileAstId::from_raw(1), + ast_id: ROOT_ERASED_FILE_AST_ID, }, ctx: SyntaxContext::root(span::Edition::CURRENT), }; @@ -84,7 +96,7 @@ fn assert_expand_impl( range: TextRange::new(0.into(), 100.into()), anchor: SpanAnchor { file_id: EditionedFileId::current_edition(FileId::from_raw(42)), - ast_id: ErasedFileAstId::from_raw(2), + ast_id: ROOT_ERASED_FILE_AST_ID, }, ctx: SyntaxContext::root(span::Edition::CURRENT), }; @@ -98,7 +110,17 @@ fn assert_expand_impl( let fixture_string = format!("{fixture:?}"); let attr_string = attr.as_ref().map(|it| format!("{it:?}")); - let res = expander.expand(macro_name, fixture, attr, def_site, call_site, mixed_site).unwrap(); + let res = expander + .expand( + macro_name, + fixture, + attr, + def_site, + call_site, + mixed_site, + FIXUP_ERASED_FILE_AST_ID_MARKER, + ) + .unwrap(); expect_spanned .assert_eq(&format!("{fixture_string}\n\n{}\n\n{res:#?}", attr_string.unwrap_or_default())); } diff --git a/crates/span/Cargo.toml b/crates/span/Cargo.toml index b3b401c3db..966962bab3 100644 --- a/crates/span/Cargo.toml +++ b/crates/span/Cargo.toml @@ -22,6 +22,9 @@ vfs.workspace = true syntax.workspace = true stdx.workspace = true +[dev-dependencies] +syntax.workspace = true + [features] default = ["salsa"] diff --git a/crates/span/src/ast_id.rs b/crates/span/src/ast_id.rs index 228fba1fa0..51a693ca01 100644 --- a/crates/span/src/ast_id.rs +++ b/crates/span/src/ast_id.rs @@ -4,137 +4,534 @@ //! Specifically, it enumerates all items in a file and uses position of a an //! item as an ID. That way, id's don't change unless the set of items itself //! changes. +//! +//! These IDs are tricky. If one of them invalidates, its interned ID invalidates, +//! and this can cause *a lot* to be recomputed. For example, if you invalidate the ID +//! of a struct, and that struct has an impl (any impl!) this will cause the `Self` +//! type of the impl to invalidate, which will cause the all impls queries to be +//! invalidated, which will cause every trait solve query in this crate *and* all +//! transitive reverse dependencies to be invalidated, which is pretty much the worst +//! thing that can happen incrementality wise. +//! +//! So we want these IDs to stay as stable as possible. For top-level items, we store +//! their kind and name, which should be unique, but since they can still not be, we +//! also store an index disambiguator. For nested items, we also store the ID of their +//! parent. For macro calls, we store the macro name and an index. There aren't usually +//! a lot of macro calls in item position, and invalidation in bodies is not much of +//! a problem, so this should be enough. use std::{ any::type_name, fmt, - hash::{BuildHasher, BuildHasherDefault, Hash, Hasher}, + hash::{BuildHasher, Hash, Hasher}, marker::PhantomData, }; use la_arena::{Arena, Idx, RawIdx}; -use rustc_hash::FxHasher; -use syntax::{AstNode, AstPtr, SyntaxNode, SyntaxNodePtr, ast}; +use rustc_hash::{FxBuildHasher, FxHashMap}; +use syntax::{ + AstNode, AstPtr, SyntaxKind, SyntaxNode, SyntaxNodePtr, + ast::{self, HasName}, + match_ast, +}; + +// The first index is always the root node's AstId +/// The root ast id always points to the encompassing file, using this in spans is discouraged as +/// any range relative to it will be effectively absolute, ruining the entire point of anchored +/// relative text ranges. +pub const ROOT_ERASED_FILE_AST_ID: ErasedFileAstId = + ErasedFileAstId(pack_hash_index_and_kind(0, 0, ErasedFileAstIdKind::Root as u32)); + +/// ErasedFileAstId used as the span for syntax node fixups. Any Span containing this file id is to be +/// considered fake. +pub const FIXUP_ERASED_FILE_AST_ID_MARKER: ErasedFileAstId = + ErasedFileAstId(pack_hash_index_and_kind(0, 0, ErasedFileAstIdKind::Fixup as u32)); -/// See crates\hir-expand\src\ast_id_map.rs /// This is a type erased FileAstId. -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, Hash)] pub struct ErasedFileAstId(u32); -impl ErasedFileAstId { - pub const fn into_raw(self) -> u32 { - self.0 - } - pub const fn from_raw(u32: u32) -> Self { - Self(u32) - } -} - -impl fmt::Display for ErasedFileAstId { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} impl fmt::Debug for ErasedFileAstId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) + 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() + } } } -/// `AstId` points to an AST node in a specific file. -pub struct FileAstId { - raw: ErasedFileAstId, - covariant: PhantomData N>, +#[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, } -impl Clone for FileAstId { +// First hash, then index, then kind. +const HASH_BITS: u32 = 16; +const INDEX_BITS: u32 = 11; +const KIND_BITS: u32 = 5; +const _: () = assert!(ErasedFileAstIdKind::Fixup as u32 <= ((1 << KIND_BITS) - 1)); +const _: () = assert!(HASH_BITS + INDEX_BITS + KIND_BITS == u32::BITS); + +#[inline] +const fn u16_hash(hash: u64) -> u16 { + // We do basically the same as `FxHasher`. We don't use rustc-hash and truncate because the + // higher bits have more entropy, but unlike rustc-hash we don't rotate because it rotates + // for hashmaps that just use the low bits, but we compare all bits. + const K: u16 = 0xecc5; + let (part1, part2, part3, part4) = + (hash as u16, (hash >> 16) as u16, (hash >> 32) as u16, (hash >> 48) as u16); + part1 + .wrapping_add(part2) + .wrapping_mul(K) + .wrapping_add(part3) + .wrapping_mul(K) + .wrapping_add(part4) + .wrapping_mul(K) +} + +#[inline] +const fn pack_hash_index_and_kind(hash: u16, index: u32, kind: u32) -> u32 { + (hash as u32) | (index << HASH_BITS) | (kind << (HASH_BITS + INDEX_BITS)) +} + +impl ErasedFileAstId { + #[inline] + fn hash_value(self) -> u16 { + self.0 as u16 + } + + #[inline] + fn index(self) -> u32 { + (self.0 << KIND_BITS) >> (HASH_BITS + KIND_BITS) + } + + #[inline] + fn kind(self) -> u32 { + self.0 >> (HASH_BITS + INDEX_BITS) + } + + 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 { + raw: ErasedFileAstId, + _marker: PhantomData N>, +} + +/// 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() @@ -148,31 +545,116 @@ impl PartialEq for AstIdMap { } impl Eq for AstIdMap {} +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum ContainsItems { + Yes, + No, +} + impl AstIdMap { pub fn from_source(node: &SyntaxNode) -> AstIdMap { assert!(node.parent().is_none()); let mut res = AstIdMap::default(); + let mut index_map = ErasedAstIdNextIndexMap::default(); + + // Ensure we allocate the root. + res.arena.alloc((SyntaxNodePtr::new(node), ROOT_ERASED_FILE_AST_ID)); - // make sure to allocate the root node - if !should_alloc_id(node.kind()) { - res.alloc(node); - } // By walking the tree in breadth-first order we make sure that parents // get lower ids then children. That is, adding a new child does not // change parent's id. This means that, say, adding a new function to a // trait does not change ids of top-level items, which helps caching. - bdfs(node, |it| { - if should_alloc_id(it.kind()) { - res.alloc(&it); - TreeOrder::BreadthFirst - } else { - TreeOrder::DepthFirst + + // This contains the stack of the `BlockExpr`s we are under. We do this + // so we only allocate `BlockExpr`s if they contain items. + // The general idea is: when we enter a block we push `(block, false)` here. + // Items inside the block are attributed to the block's container, not the block. + // For the first item we find inside a block, we make this `(block, true)` + // and create an ast id for the block. When exiting the block we pop it, + // whether or not we created an ast id for it. + // It may seem that with this setup we will generate an ID for blocks that + // have no items directly but have items inside other items inside them. + // This is true, but it doesn't matter, because such blocks can't exist. + // After all, the block will then contain the *outer* item, so we allocate + // an ID for it anyway. + let mut blocks = Vec::new(); + let mut curr_layer = vec![(node.clone(), None)]; + let mut next_layer = vec![]; + while !curr_layer.is_empty() { + curr_layer.drain(..).for_each(|(node, parent_idx)| { + let mut preorder = node.preorder(); + while let Some(event) = preorder.next() { + match event { + syntax::WalkEvent::Enter(node) => { + if ast::BlockExpr::can_cast(node.kind()) { + blocks.push((node, ContainsItems::No)); + } else if ErasedFileAstId::should_alloc(&node) { + // Allocate blocks on-demand, only if they have items. + // We don't associate items with blocks, only with items, since block IDs can be quite unstable. + // FIXME: Is this the correct thing to do? Macro calls might actually be more incremental if + // associated with blocks (not sure). Either way it's not a big deal. + if let Some(( + last_block_node, + already_allocated @ ContainsItems::No, + )) = blocks.last_mut() + { + let block_ast_id = block_expr_ast_id( + last_block_node, + &mut index_map, + parent_of(parent_idx, &res), + ) + .expect("not a BlockExpr"); + res.arena + .alloc((SyntaxNodePtr::new(last_block_node), block_ast_id)); + *already_allocated = ContainsItems::Yes; + } + + let parent = parent_of(parent_idx, &res); + let ast_id = + ErasedFileAstId::ast_id_for(&node, &mut index_map, parent) + .expect("this node should have an ast id"); + let idx = res.arena.alloc((SyntaxNodePtr::new(&node), ast_id)); + + next_layer.extend(node.children().map(|child| (child, Some(idx)))); + preorder.skip_subtree(); + } + } + syntax::WalkEvent::Leave(node) => { + if ast::BlockExpr::can_cast(node.kind()) { + assert_eq!( + blocks.pop().map(|it| it.0), + Some(node), + "left a BlockExpr we never entered" + ); + } + } + } + } + }); + std::mem::swap(&mut curr_layer, &mut next_layer); + assert!(blocks.is_empty(), "didn't leave all BlockExprs"); + } + + res.ptr_map = hashbrown::HashTable::with_capacity(res.arena.len()); + res.id_map = hashbrown::HashTable::with_capacity(res.arena.len()); + for (idx, (ptr, ast_id)) in res.arena.iter() { + let ptr_hash = hash_ptr(ptr); + let ast_id_hash = hash_ast_id(ast_id); + match res.ptr_map.entry( + ptr_hash, + |idx2| *idx2 == idx, + |&idx| hash_ptr(&res.arena[idx].0), + ) { + hashbrown::hash_table::Entry::Occupied(_) => unreachable!(), + hashbrown::hash_table::Entry::Vacant(entry) => { + entry.insert(idx); + } } - }); - res.map = hashbrown::HashTable::with_capacity(res.arena.len()); - for (idx, ptr) in res.arena.iter() { - let hash = hash_ptr(ptr); - match res.map.entry(hash, |&idx2| idx2 == idx, |&idx| hash_ptr(&res.arena[idx])) { + match res.id_map.entry( + ast_id_hash, + |idx2| *idx2 == idx, + |&idx| hash_ast_id(&res.arena[idx].1), + ) { hashbrown::hash_table::Entry::Occupied(_) => unreachable!(), hashbrown::hash_table::Entry::Vacant(entry) => { entry.insert(idx); @@ -180,98 +662,235 @@ impl AstIdMap { } } res.arena.shrink_to_fit(); - res + return res; + + fn parent_of(parent_idx: Option, res: &AstIdMap) -> Option<&ErasedFileAstId> { + let mut parent = parent_idx.map(|parent_idx| &res.arena[parent_idx].1); + if parent.is_some_and(|parent| parent.kind() == ErasedFileAstIdKind::ExternBlock as u32) + { + // See the comment on `ErasedAssocItemFileAstId` for why is this. + // FIXME: Technically there could be an extern block inside another item, e.g.: + // ``` + // fn foo() { + // extern "C" { + // fn bar(); + // } + // } + // ``` + // Here we want to make `foo()` the parent of `bar()`, but we make it `None`. + // Shouldn't be a big deal though. + parent = None; + } + parent + } } /// The [`AstId`] of the root node pub fn root(&self) -> SyntaxNodePtr { - self.arena[Idx::from_raw(RawIdx::from_u32(0))] + self.arena[Idx::from_raw(RawIdx::from_u32(0))].0 } pub fn ast_id(&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{:?}", - ptr, - self.arena.iter().map(|(_id, i)| i).collect::>(), - ), - } + FileAstId { raw: self.erased_ast_id(ptr), _marker: PhantomData } } - pub fn get(&self, id: FileAstId) -> AstPtr { - AstPtr::try_from_raw(self.arena[Idx::from_raw(RawIdx::from_u32(id.raw.into_raw()))]) - .unwrap() + /// 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::>(), + ) + }) + } + + 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) + } + + // 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:?}`")) } pub fn get_erased(&self, id: ErasedFileAstId) -> SyntaxNodePtr { - self.arena[Idx::from_raw(RawIdx::from_u32(id.into_raw()))] - } - - 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()), + 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) + FxBuildHasher.hash_one(ptr) } -#[derive(Copy, Clone, PartialEq, Eq)] -enum TreeOrder { - BreadthFirst, - DepthFirst, +#[inline] +fn hash_ast_id(ptr: &ErasedFileAstId) -> u64 { + FxBuildHasher.hash_one(ptr) } -/// 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(_) => {} - } +#[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 f81648ac42..b81d08eed6 100644 --- a/crates/span/src/lib.rs +++ b/crates/span/src/lib.rs @@ -6,7 +6,10 @@ mod hygiene; mod map; pub use self::{ - ast_id::{AstIdMap, AstIdNode, ErasedFileAstId, FileAstId}, + ast_id::{ + AstIdMap, AstIdNode, ErasedFileAstId, FIXUP_ERASED_FILE_AST_ID_MARKER, FileAstId, + ROOT_ERASED_FILE_AST_ID, + }, hygiene::{SyntaxContext, Transparency}, map::{RealSpanMap, SpanMap}, }; @@ -15,19 +18,6 @@ pub use syntax::Edition; pub use text_size::{TextRange, TextSize}; pub use vfs::FileId; -// The first index is always the root node's AstId -/// The root ast id always points to the encompassing file, using this in spans is discouraged as -/// any range relative to it will be effectively absolute, ruining the entire point of anchored -/// relative text ranges. -pub const ROOT_ERASED_FILE_AST_ID: ErasedFileAstId = ErasedFileAstId::from_raw(0); - -/// FileId used as the span for syntax node fixups. Any Span containing this file id is to be -/// considered fake. -pub const FIXUP_ERASED_FILE_AST_ID_MARKER: ErasedFileAstId = - // we pick the second to last for this in case we ever consider making this a NonMaxU32, this - // is required to be stable for the proc-macro-server - ErasedFileAstId::from_raw(!0 - 1); - pub type Span = SpanData; 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 cc7a886643..f58201793d 100644 --- a/crates/span/src/map.rs +++ b/crates/span/src/map.rs @@ -169,7 +169,7 @@ impl fmt::Display for RealSpanMap { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { writeln!(f, "RealSpanMap({:?}):", self.file_id)?; for span in self.pairs.iter() { - writeln!(f, "{}: {}", u32::from(span.0), span.1.into_raw())?; + writeln!(f, "{}: {:#?}", u32::from(span.0), span.1)?; } Ok(()) } diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs index dcf853427e..f5530c5fff 100644 --- a/crates/syntax/src/ast/node_ext.rs +++ b/crates/syntax/src/ast/node_ext.rs @@ -30,6 +30,16 @@ impl ast::Name { pub fn text(&self) -> TokenText<'_> { text_of_first_token(self.syntax()) } + pub fn text_non_mutable(&self) -> &str { + fn first_token(green_ref: &GreenNodeData) -> &GreenTokenData { + green_ref.children().next().and_then(NodeOrToken::into_token).unwrap() + } + + match self.syntax().green() { + Cow::Borrowed(green_ref) => first_token(green_ref).text(), + Cow::Owned(_) => unreachable!(), + } + } } impl ast::NameRef { From ed0b4506dde9b615a8026a6ef8d35353eb9cd94a Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Wed, 21 May 2025 13:13:34 +0300 Subject: [PATCH 11/56] Avoid referring to the item tree except in the def map Item tree IDs are very unstable (adding an item of a kind invalidates all following items of the same kind). Instead use ast ids, which, since the previous commit, are pretty stable. --- crates/hir-def/src/attr.rs | 156 ++++--- crates/hir-def/src/db.rs | 36 +- crates/hir-def/src/expr_store/expander.rs | 7 + crates/hir-def/src/expr_store/lower.rs | 19 +- crates/hir-def/src/expr_store/pretty.rs | 76 ++-- crates/hir-def/src/item_tree.rs | 42 +- crates/hir-def/src/item_tree/lower.rs | 2 +- crates/hir-def/src/item_tree/pretty.rs | 2 +- crates/hir-def/src/item_tree/tests.rs | 2 +- crates/hir-def/src/lang_item.rs | 2 +- crates/hir-def/src/lib.rs | 187 ++++---- crates/hir-def/src/nameres.rs | 2 - crates/hir-def/src/nameres/assoc.rs | 214 ++++++---- crates/hir-def/src/nameres/collector.rs | 176 ++++---- crates/hir-def/src/nameres/diagnostics.rs | 25 +- crates/hir-def/src/nameres/path_resolution.rs | 34 +- crates/hir-def/src/resolver.rs | 36 +- crates/hir-def/src/signatures.rs | 400 +++++++++--------- crates/hir-def/src/src.rs | 106 +++-- crates/hir-def/src/visibility.rs | 82 ++-- crates/hir-expand/src/files.rs | 9 +- crates/hir-ty/src/chalk_db.rs | 2 +- crates/hir-ty/src/diagnostics/decl_check.rs | 4 +- .../diagnostics/match_check/pat_analysis.rs | 2 +- crates/hir-ty/src/drop.rs | 2 +- crates/hir-ty/src/inhabitedness.rs | 2 +- crates/hir-ty/src/layout/adt.rs | 2 +- crates/hir-ty/src/mir/eval.rs | 9 +- crates/hir-ty/src/mir/eval/shim.rs | 7 +- crates/hir-ty/src/mir/lower.rs | 9 +- crates/hir-ty/src/mir/pretty.rs | 13 +- crates/hir-ty/src/tests.rs | 2 +- crates/hir-ty/src/tests/incremental.rs | 3 +- crates/hir-ty/src/utils.rs | 4 +- crates/hir-ty/src/variance.rs | 2 +- crates/hir/src/lib.rs | 233 ++++------ crates/hir/src/semantics/child_by_source.rs | 25 +- 37 files changed, 981 insertions(+), 955 deletions(-) diff --git a/crates/hir-def/src/attr.rs b/crates/hir-def/src/attr.rs index bb6222b1d4..a7328809a8 100644 --- a/crates/hir-def/src/attr.rs +++ b/crates/hir-def/src/attr.rs @@ -14,6 +14,7 @@ use intern::{Symbol, sym}; use la_arena::{ArenaMap, Idx, RawIdx}; use mbe::DelimiterKind; use rustc_abi::ReprOptions; +use span::AstIdNode; use syntax::{ AstPtr, ast::{self, HasAttrs}, @@ -22,10 +23,10 @@ use triomphe::Arc; use tt::iter::{TtElement, TtIter}; use crate::{ - AdtId, AttrDefId, GenericParamId, HasModule, ItemTreeLoc, LocalFieldId, Lookup, MacroId, + AdtId, AstIdLoc, AttrDefId, GenericParamId, HasModule, LocalFieldId, Lookup, MacroId, VariantId, db::DefDatabase, - item_tree::{AttrOwner, FieldParent, ItemTreeNode}, + item_tree::AttrOwner, lang_item::LangItem, nameres::{ModuleOrigin, ModuleSource}, src::{HasChildSource, HasSource}, @@ -42,6 +43,15 @@ pub struct AttrsWithOwner { } impl Attrs { + pub fn new( + db: &dyn DefDatabase, + owner: &dyn ast::HasAttrs, + span_map: SpanMapRef<'_>, + cfg_options: &CfgOptions, + ) -> Self { + Attrs(RawAttrs::new_expanded(db, owner, span_map, cfg_options)) + } + pub fn get(&self, id: AttrId) -> Option<&Attr> { (**self).iter().find(|attr| attr.id == id) } @@ -94,44 +104,64 @@ impl Attrs { v: VariantId, ) -> Arc> { 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 span_map = db.span_map(file_id); - 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; + 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() } - } + }; + Attrs::expand_cfg_attr(db, module.krate, raw_attrs) } - AttrDefId::FieldId(it) => { - return db.fields_attrs(it.parent)[it.local_id].clone(); - } - 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 4a9a3b12cf..362c0daa9b 100644 --- a/crates/hir-def/src/db.rs +++ b/crates/hir-def/src/db.rs @@ -1,8 +1,11 @@ //! Defines database & queries for name resolution. use base_db::{Crate, RootQueryDb, SourceDatabase}; use either::Either; -use hir_expand::{EditionedFileId, HirFileId, MacroCallId, MacroDefId, db::ExpandDatabase}; -use intern::sym; +use hir_expand::{ + EditionedFileId, HirFileId, InFile, Lookup, MacroCallId, MacroDefId, MacroDefKind, + db::ExpandDatabase, +}; +use intern::{Symbol, sym}; use la_arena::ArenaMap; use syntax::{AstPtr, ast}; use thin_vec::ThinVec; @@ -11,8 +14,8 @@ use triomphe::Arc; use crate::{ AttrDefId, BlockId, BlockLoc, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, EnumVariantId, EnumVariantLoc, ExternBlockId, ExternBlockLoc, ExternCrateId, ExternCrateLoc, FunctionId, - FunctionLoc, GenericDefId, ImplId, ImplLoc, LocalFieldId, Macro2Id, Macro2Loc, MacroId, - MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ProcMacroId, ProcMacroLoc, StaticId, + FunctionLoc, GenericDefId, ImplId, ImplLoc, LocalFieldId, Macro2Id, Macro2Loc, MacroExpander, + MacroId, MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ProcMacroId, ProcMacroLoc, StaticId, StaticLoc, StructId, StructLoc, TraitAliasId, TraitAliasLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, UseId, UseLoc, VariantId, attr::{Attrs, AttrsWithOwner}, @@ -123,6 +126,8 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + SourceDatabase { id: VariantId, ) -> (Arc, 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)] @@ -399,10 +407,6 @@ fn crate_supports_no_std(db: &dyn DefDatabase, crate_id: Crate) -> bool { } fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId { - use hir_expand::InFile; - - use crate::{Lookup, MacroDefKind, MacroExpander}; - let kind = |expander, file_id, m| { let in_file = InFile::new(file_id, m); match expander { @@ -418,11 +422,9 @@ fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId { MacroId::Macro2Id(it) => { let loc: Macro2Loc = it.lookup(db); - let item_tree = loc.id.item_tree(db); - let makro = &item_tree[loc.id.value]; MacroDefId { krate: loc.container.krate, - kind: kind(loc.expander, loc.id.file_id(), makro.ast_id.upcast()), + kind: kind(loc.expander, loc.id.file_id, loc.id.value.upcast()), local_inner: false, allow_internal_unsafe: loc.allow_internal_unsafe, edition: loc.edition, @@ -431,11 +433,9 @@ fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId { MacroId::MacroRulesId(it) => { let loc: MacroRulesLoc = it.lookup(db); - let item_tree = loc.id.item_tree(db); - let makro = &item_tree[loc.id.value]; MacroDefId { krate: loc.container.krate, - kind: kind(loc.expander, loc.id.file_id(), makro.ast_id.upcast()), + kind: kind(loc.expander, loc.id.file_id, loc.id.value.upcast()), local_inner: loc.flags.contains(MacroRulesLocFlags::LOCAL_INNER), allow_internal_unsafe: loc .flags @@ -446,15 +446,9 @@ fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId { MacroId::ProcMacroId(it) => { let loc = it.lookup(db); - let item_tree = loc.id.item_tree(db); - let makro = &item_tree[loc.id.value]; MacroDefId { krate: loc.container.krate, - kind: MacroDefKind::ProcMacro( - InFile::new(loc.id.file_id(), makro.ast_id), - loc.expander, - loc.kind, - ), + kind: MacroDefKind::ProcMacro(loc.id, loc.expander, loc.kind), local_inner: false, allow_internal_unsafe: false, edition: loc.edition, diff --git a/crates/hir-def/src/expr_store/expander.rs b/crates/hir-def/src/expr_store/expander.rs index 3823fb5a1e..23b9712d1e 100644 --- a/crates/hir-def/src/expr_store/expander.rs +++ b/crates/hir-def/src/expr_store/expander.rs @@ -6,6 +6,7 @@ use base_db::Crate; use cfg::CfgOptions; use drop_bomb::DropBomb; use hir_expand::AstId; +use hir_expand::span_map::SpanMapRef; use hir_expand::{ ExpandError, ExpandErrorKind, ExpandResult, HirFileId, InFile, Lookup, MacroCallId, eager::EagerCallBackFn, mod_path::ModPath, span_map::SpanMap, @@ -223,9 +224,15 @@ impl Expander { } } + #[inline] pub(super) fn ast_id_map(&self) -> &AstIdMap { &self.ast_id_map } + + #[inline] + pub(super) fn span_map(&self) -> SpanMapRef<'_> { + self.span_map.as_ref() + } } #[derive(Debug)] diff --git a/crates/hir-def/src/expr_store/lower.rs b/crates/hir-def/src/expr_store/lower.rs index b7a482a85d..89eeaf00bc 100644 --- a/crates/hir-def/src/expr_store/lower.rs +++ b/crates/hir-def/src/expr_store/lower.rs @@ -10,9 +10,10 @@ use std::mem; use cfg::CfgOptions; use either::Either; use hir_expand::{ - HirFileId, InFile, Lookup, MacroDefId, + HirFileId, InFile, MacroDefId, mod_path::tool_path, name::{AsName, Name}, + span_map::SpanMapRef, }; use intern::{Symbol, sym}; use rustc_hash::FxHashMap; @@ -30,8 +31,8 @@ use triomphe::Arc; use tt::TextRange; use crate::{ - AdtId, BlockId, BlockLoc, DefWithBodyId, FunctionId, GenericDefId, ImplId, ItemTreeLoc, - MacroId, ModuleDefId, ModuleId, TraitAliasId, TraitId, TypeAliasId, UnresolvedMacro, + AdtId, BlockId, BlockLoc, DefWithBodyId, FunctionId, GenericDefId, ImplId, MacroId, + ModuleDefId, ModuleId, TraitAliasId, TraitId, TypeAliasId, UnresolvedMacro, builtin_type::BuiltinUint, db::DefDatabase, expr_store::{ @@ -564,6 +565,11 @@ impl ExprCollector<'_> { } } + #[inline] + pub(crate) fn span_map(&self) -> SpanMapRef<'_> { + self.expander.span_map() + } + pub fn lower_lifetime_ref(&mut self, lifetime: ast::Lifetime) -> LifetimeRefId { // FIXME: Keyword check? let lifetime_ref = match &*lifetime.text() { @@ -2244,11 +2250,8 @@ impl ExprCollector<'_> { match resolved.take_values() { Some(ModuleDefId::ConstId(_)) => (None, Pat::Path(name.into())), Some(ModuleDefId::EnumVariantId(variant)) - if { - let loc = variant.lookup(self.db); - let tree = loc.item_tree_id().item_tree(self.db); - tree[loc.id.value].shape != FieldsShape::Record - } => + // FIXME: This can cause a cycle if the user is writing invalid code + if self.db.variant_fields(variant.into()).shape != FieldsShape::Record => { (None, Pat::Path(name.into())) } diff --git a/crates/hir-def/src/expr_store/pretty.rs b/crates/hir-def/src/expr_store/pretty.rs index f12a9b7a54..7b452721df 100644 --- a/crates/hir-def/src/expr_store/pretty.rs +++ b/crates/hir-def/src/expr_store/pretty.rs @@ -9,9 +9,10 @@ use std::{ use hir_expand::{Lookup, mod_path::PathKind}; use itertools::Itertools; use span::Edition; +use syntax::ast::HasName; use crate::{ - AdtId, DefWithBodyId, GenericDefId, ItemTreeLoc, TypeParamId, VariantId, + AdtId, DefWithBodyId, GenericDefId, TypeParamId, VariantId, expr_store::path::{GenericArg, GenericArgs}, hir::{ Array, BindingAnnotation, CaptureBy, ClosureKind, Literal, Movability, Statement, @@ -19,6 +20,7 @@ use crate::{ }, lang_item::LangItemTarget, signatures::{FnFlags, FunctionSignature, StructSignature}, + src::HasSource, type_ref::{ConstRef, LifetimeRef, Mutability, TraitBoundModifier, TypeBound, UseArgRef}, }; use crate::{LifetimeParamId, signatures::StructFlags}; @@ -48,6 +50,17 @@ pub enum LineFormat { Indentation, } +fn item_name(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 1b97eb72b6..65dc35337a 100644 --- a/crates/hir-def/src/item_tree.rs +++ b/crates/hir-def/src/item_tree.rs @@ -46,7 +46,7 @@ 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, @@ -62,6 +62,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); @@ -446,6 +448,7 @@ impl TreeId { } } + #[inline] pub fn file_id(self) -> HirFileId { self.file } @@ -878,43 +881,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. diff --git a/crates/hir-def/src/item_tree/lower.rs b/crates/hir-def/src/item_tree/lower.rs index b490e1683c..5776542769 100644 --- a/crates/hir-def/src/item_tree/lower.rs +++ b/crates/hir-def/src/item_tree/lower.rs @@ -626,7 +626,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, diff --git a/crates/hir-def/src/item_tree/pretty.rs b/crates/hir-def/src/item_tree/pretty.rs index 51172c0a1e..8ff14751c6 100644 --- a/crates/hir-def/src/item_tree/pretty.rs +++ b/crates/hir-def/src/item_tree/pretty.rs @@ -258,7 +258,7 @@ impl Printer<'_> { let Enum { name, visibility, variants, 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)); + w!(self, "enum {} {{", name.display(self.db, self.edition)); let edition = self.edition; self.indented(|this| { for variant in FileItemTreeId::range_iter(variants.clone()) { diff --git a/crates/hir-def/src/item_tree/tests.rs b/crates/hir-def/src/item_tree/tests.rs index abfff283ef..7a85e8d175 100644 --- a/crates/hir-def/src/item_tree/tests.rs +++ b/crates/hir-def/src/item_tree/tests.rs @@ -147,7 +147,7 @@ enum E { } // AstId: Enum[7FF8, 0] - pub(self) enum E + pub(self) enum E { // AstId: Variant[C717, 0] #[doc = " comment on Unit"] Unit, diff --git a/crates/hir-def/src/lang_item.rs b/crates/hir-def/src/lang_item.rs index 4ad44775ea..1614ef0da4 100644 --- a/crates/hir-def/src/lang_item.rs +++ b/crates/hir-def/src/lang_item.rs @@ -125,7 +125,7 @@ pub fn crate_lang_items(db: &dyn DefDatabase, krate: Crate) -> Option { lang_items.collect_lang_item(db, e, LangItemTarget::EnumId); - db.enum_variants(e).variants.iter().for_each(|&(id, _)| { + db.enum_variants(e).variants.iter().for_each(|&(id, _, _)| { lang_items.collect_lang_item(db, id, LangItemTarget::EnumVariant); }); } diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs index 1e8859a9cc..dcc18666a5 100644 --- a/crates/hir-def/src/lib.rs +++ b/crates/hir-def/src/lib.rs @@ -74,12 +74,11 @@ use hir_expand::{ name::Name, proc_macro::{CustomProcMacroExpander, ProcMacroKind}, }; -use item_tree::ExternBlock; use la_arena::Idx; use nameres::DefMap; use span::{AstIdNode, Edition, FileAstId, SyntaxContext}; use stdx::impl_from; -use syntax::ast; +use syntax::{AstNode, ast}; pub use hir_expand::{Intern, Lookup, tt}; @@ -88,10 +87,6 @@ use crate::{ builtin_type::BuiltinType, db::DefDatabase, hir::generics::{LocalLifetimeParamId, LocalTypeOrConstParamId}, - item_tree::{ - Const, Enum, ExternCrate, Function, Impl, ItemTreeId, ItemTreeNode, Macro2, MacroRules, - Static, Struct, Trait, TraitAlias, TypeAlias, Union, Use, Variant, - }, nameres::{LocalDefMap, block_def_map, crate_def_map, crate_local_def_map}, signatures::VariantFields, }; @@ -113,70 +108,110 @@ pub struct ImportPathConfig { } #[derive(Debug)] -pub struct ItemLoc { +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/nameres.rs b/crates/hir-def/src/nameres.rs index f337f83156..c908e45754 100644 --- a/crates/hir-def/src/nameres.rs +++ b/crates/hir-def/src/nameres.rs @@ -171,12 +171,10 @@ pub struct DefMap { /// ExternCrateId being None implies it being imported from the general prelude import. macro_use_prelude: FxHashMap)>, - // 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 86225d33b4..cf123d14f5 100644 --- a/crates/hir-def/src/nameres/assoc.rs +++ b/crates/hir-def/src/nameres/assoc.rs @@ -1,14 +1,28 @@ //! Expansion of associated items -use hir_expand::{AstId, InFile, Intern, Lookup, MacroCallKind, MacroDefKind, name::Name}; -use syntax::ast; +use std::mem; + +use cfg::CfgOptions; +use hir_expand::{ + AstId, ExpandTo, HirFileId, InFile, Intern, Lookup, MacroCallKind, MacroDefKind, + mod_path::ModPath, + name::{AsName, Name}, + span_map::SpanMap, +}; +use intern::Interned; +use span::AstIdMap; +use syntax::{ + AstNode, + ast::{self, HasModuleItem, HasName}, +}; +use thin_vec::ThinVec; use triomphe::Arc; use crate::{ AssocItemId, AstIdWithPath, ConstLoc, FunctionId, FunctionLoc, ImplId, ItemContainerId, ItemLoc, MacroCallId, ModuleId, TraitId, TypeAliasId, TypeAliasLoc, + attr::Attrs, db::DefDatabase, - item_tree::{AssocItem, ItemTree, ItemTreeId, MacroCall, ModItem, TreeId}, macro_call_as_call_id, nameres::{ DefMap, LocalDefMap, MacroSubNs, @@ -20,9 +34,8 @@ use crate::{ #[derive(Debug, Clone, PartialEq, Eq)] pub struct TraitItems { pub items: Box<[(Name, AssocItemId)]>, - // box it as the vec is usually empty anyways - // FIXME: AstIds are rather unstable... - pub macro_calls: Option, 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 macro_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 macro_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]; + 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())); + } + ast::AssocItem::Const(konst) => { + let Some(name) = konst.name() else { return }; + let ast_id = self.ast_id_map.ast_id(&konst); let def = - FunctionLoc { 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())); + self.items.push((name.as_name(), def.into())); } - AssocItem::TypeAlias(id) => { - let item = &item_tree[id]; - let def = - TypeAliasLoc { container: self.container, id: ItemTreeId::new(tree_id, 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())); - } - AssocItem::MacroCall(call) => { - let MacroCall { ast_id, expand_to, ctxt, ref path } = item_tree[call]; + ast::AssocItem::MacroCall(call) => { + let ast_id = self.ast_id_map.ast_id(&call); + let ast_id = InFile::new(self.file_id, ast_id); + let Some(path) = call.path() else { return }; + let range = path.syntax().text_range(); + let Some(path) = ModPath::from_src(self.db, path, &mut |range| { + self.span_map.span_for_range(range).ctx + }) else { + return; + }; + let path = Interned::new(path); + let ctxt = self.span_map.span_for_range(range).ctx; let resolver = |path: &_| { self.def_map @@ -268,10 +303,10 @@ impl<'a> AssocItemCollector<'a> { }; match macro_call_as_call_id( self.db, - InFile::new(tree_id.file_id(), ast_id), - path, + ast_id, + &path, ctxt, - expand_to, + ExpandTo::Items, self.module_id.krate(), resolver, &mut |ptr, call_id| { @@ -281,8 +316,7 @@ impl<'a> AssocItemCollector<'a> { // FIXME: Expansion error? Ok(call_id) => match call_id.value { Some(call_id) => { - self.macro_calls - .push((InFile::new(tree_id.file_id(), ast_id.upcast()), call_id)); + self.macro_calls.push((ast_id.upcast(), call_id)); self.collect_macro_items(call_id); } None => (), @@ -291,11 +325,11 @@ impl<'a> AssocItemCollector<'a> { self.diagnostics.push(DefDiagnostic::unresolved_macro_call( self.module_id.local_id, MacroCallKind::FnLike { - ast_id: InFile::new(tree_id.file_id(), ast_id), - expand_to, + ast_id, + expand_to: ExpandTo::Items, eager: None, }, - Clone::clone(path), + (*path).clone(), )); } } @@ -308,13 +342,29 @@ impl<'a> AssocItemCollector<'a> { tracing::warn!("macro expansion is too deep"); return; } - let tree_id = TreeId::new(macro_call_id.into(), None); - let item_tree = self.db.file_item_tree(macro_call_id.into()); + let (syntax, span_map) = self.db.parse_macro_expansion(macro_call_id).value; + let old_file_id = mem::replace(&mut self.file_id, macro_call_id.into()); + let old_ast_id_map = mem::replace(&mut self.ast_id_map, self.db.ast_id_map(self.file_id)); + let old_span_map = mem::replace(&mut self.span_map, SpanMap::ExpansionSpanMap(span_map)); self.depth += 1; - for item in item_tree.top_level_items().iter().filter_map(ModItem::as_assoc_item) { - self.collect_item(&item_tree, tree_id, item); + + let items = ast::MacroItems::cast(syntax.syntax_node()).expect("not `MacroItems`"); + for item in items.items() { + let item = match item { + ast::Item::Fn(it) => ast::AssocItem::from(it), + ast::Item::Const(it) => it.into(), + ast::Item::TypeAlias(it) => it.into(), + ast::Item::MacroCall(it) => it.into(), + // FIXME: Should error on disallowed item kinds. + _ => continue, + }; + self.collect_item(item); } + self.depth -= 1; + self.file_id = old_file_id; + self.ast_id_map = old_ast_id_map; + self.span_map = old_span_map; } } diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index 350c97c398..34a129a88e 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -9,8 +9,8 @@ use base_db::{BuiltDependency, Crate, CrateOrigin, LangCrateOrigin}; use cfg::{CfgAtom, CfgExpr, CfgOptions}; use either::Either; use hir_expand::{ - EditionedFileId, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId, - MacroDefKind, + EditionedFileId, ErasedAstId, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, + MacroDefId, MacroDefKind, attrs::{Attr, AttrId}, builtin::{find_builtin_attr, find_builtin_derive, find_builtin_macro}, mod_path::{ModPath, PathKind}, @@ -35,9 +35,8 @@ use crate::{ db::DefDatabase, item_scope::{GlobId, ImportId, ImportOrExternCrate, PerNsGlobImports}, item_tree::{ - self, AttrOwner, FieldsShape, FileItemTreeId, ImportAlias, ImportKind, ItemTree, - ItemTreeId, ItemTreeNode, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, TreeId, - UseTreeKind, + self, FieldsShape, FileItemTreeId, ImportAlias, ImportKind, ItemTree, ItemTreeId, + ItemTreeNode, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, TreeId, UseTreeKind, }, macro_call_as_call_id, nameres::{ @@ -141,6 +140,7 @@ struct ImportSource { id: UseId, is_prelude: bool, kind: ImportKind, + item_tree_id: ItemTreeId, } #[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 de3d2f4836..c495a07449 100644 --- a/crates/hir-def/src/nameres/diagnostics.rs +++ b/crates/hir-def/src/nameres/diagnostics.rs @@ -3,22 +3,18 @@ use std::ops::Not; use cfg::{CfgExpr, CfgOptions}; -use hir_expand::{ExpandErrorKind, MacroCallKind, attrs::AttrId, mod_path::ModPath}; +use hir_expand::{ErasedAstId, ExpandErrorKind, MacroCallKind, attrs::AttrId, mod_path::ModPath}; use la_arena::Idx; use syntax::ast; -use crate::{ - AstId, - item_tree::{self, AttrOwner, ItemTreeId, TreeId}, - nameres::LocalModuleId, -}; +use crate::{AstId, nameres::LocalModuleId}; #[derive(Debug, PartialEq, Eq)] pub enum DefDiagnosticKind { UnresolvedModule { ast: AstId, 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 74ce33a641..e0e32a7773 100644 --- a/crates/hir-def/src/nameres/path_resolution.rs +++ b/crates/hir-def/src/nameres/path_resolution.rs @@ -12,7 +12,6 @@ use either::Either; use hir_expand::{ - Lookup, mod_path::{ModPath, PathKind}, name::Name, }; @@ -529,23 +528,22 @@ impl DefMap { // enum variant cov_mark::hit!(can_import_enum_variant); - let res = - db.enum_variants(e).variants.iter().find(|(_, name)| name == segment).map( - |&(variant, _)| { - let item_tree_id = variant.lookup(db).id; - match item_tree_id.item_tree(db)[item_tree_id.value].shape { - FieldsShape::Record => { - PerNs::types(variant.into(), Visibility::Public, None) - } - FieldsShape::Tuple | FieldsShape::Unit => PerNs::both( - variant.into(), - variant.into(), - Visibility::Public, - None, - ), - } - }, - ); + let res = db + .enum_variants(e) + .variants + .iter() + .find(|(_, name, _)| name == segment) + .map(|&(variant, _, shape)| match shape { + FieldsShape::Record => { + PerNs::types(variant.into(), Visibility::Public, None) + } + FieldsShape::Tuple | FieldsShape::Unit => PerNs::both( + variant.into(), + variant.into(), + Visibility::Public, + None, + ), + }); // FIXME: Need to filter visibility here and below? Not sure. return match res { Some(res) => { diff --git a/crates/hir-def/src/resolver.rs b/crates/hir-def/src/resolver.rs index 16988ddf04..491b6204bc 100644 --- a/crates/hir-def/src/resolver.rs +++ b/crates/hir-def/src/resolver.rs @@ -5,21 +5,22 @@ use base_db::Crate; use hir_expand::{ MacroDefId, mod_path::{ModPath, PathKind}, - name::Name, + name::{AsName, Name}, }; use intern::{Symbol, sym}; use itertools::Itertools as _; use rustc_hash::FxHashSet; use smallvec::{SmallVec, smallvec}; use span::SyntaxContext; +use syntax::ast::HasName; use triomphe::Arc; use crate::{ - AdtId, ConstId, ConstParamId, CrateRootModuleId, DefWithBodyId, EnumId, EnumVariantId, - ExternBlockId, ExternCrateId, FunctionId, FxIndexMap, GenericDefId, GenericParamId, HasModule, - ImplId, ItemContainerId, ItemTreeLoc, LifetimeParamId, LocalModuleId, Lookup, Macro2Id, - MacroId, MacroRulesId, ModuleDefId, ModuleId, ProcMacroId, StaticId, StructId, TraitAliasId, - TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UseId, VariantId, + AdtId, AstIdLoc, ConstId, ConstParamId, CrateRootModuleId, DefWithBodyId, EnumId, + EnumVariantId, ExternBlockId, ExternCrateId, FunctionId, FxIndexMap, GenericDefId, + GenericParamId, HasModule, ImplId, ItemContainerId, LifetimeParamId, LocalModuleId, Lookup, + Macro2Id, MacroId, MacroRulesId, ModuleDefId, ModuleId, ProcMacroId, StaticId, StructId, + TraitAliasId, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UseId, VariantId, builtin_type::BuiltinType, db::DefDatabase, expr_store::{ @@ -32,10 +33,10 @@ use crate::{ generics::{GenericParams, TypeOrConstParamData}, }, item_scope::{BUILTIN_SCOPE, BuiltinShadowMode, ImportOrExternCrate, ImportOrGlob, ItemScope}, - item_tree::ImportAlias, lang_item::LangItemTarget, nameres::{DefMap, LocalDefMap, MacroSubNs, ResolvePathResultPrefixInfo, block_def_map}, per_ns::PerNs, + src::HasSource, type_ref::LifetimeRef, visibility::{RawVisibility, Visibility}, }; @@ -627,14 +628,14 @@ impl<'db> Resolver<'db> { .extern_crate_decls() .filter_map(|id| { let loc = id.lookup(db); - let tree = loc.item_tree_id().item_tree(db); - match &tree[loc.id.value].alias { - Some(alias) => match alias { - ImportAlias::Underscore => None, - ImportAlias::Alias(name) => Some(name.clone()), - }, - None => Some(tree[loc.id.value].name.clone()), - } + let extern_crate = loc.source(db); + // If there is a rename (`as x`), extract the renamed name, or remove the `extern crate` + // if it is an underscore. + extern_crate + .value + .rename() + .map(|a| a.name().map(|it| it.as_name())) + .unwrap_or_else(|| extern_crate.value.name_ref().map(|it| it.as_name())) }) } @@ -1471,10 +1472,7 @@ impl HasResolver for MacroRulesId { fn lookup_resolver( db: &dyn DefDatabase, - lookup: impl Lookup< - Database = dyn DefDatabase, - Data = impl ItemTreeLoc, - >, + 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 44cfd72c48..b7d29f54d0 100644 --- a/crates/hir-def/src/signatures.rs +++ b/crates/hir-def/src/signatures.rs @@ -4,21 +4,25 @@ use std::ops::Not as _; use bitflags::bitflags; use cfg::{CfgExpr, CfgOptions}; -use either::Either; -use hir_expand::{InFile, Intern, Lookup, name::Name}; +use hir_expand::{ + InFile, Intern, Lookup, + name::{AsName, Name}, +}; use intern::{Symbol, sym}; use la_arena::{Arena, Idx}; use rustc_abi::{IntegerType, ReprOptions}; use syntax::{ - AstNode, SyntaxNodePtr, - ast::{self, HasGenericParams, IsString}, + NodeOrToken, SyntaxNodePtr, T, + ast::{self, HasGenericParams, HasName, HasVisibility, IsString}, }; use thin_vec::ThinVec; use triomphe::Arc; use crate::{ - ConstId, EnumId, EnumVariantId, EnumVariantLoc, FunctionId, HasModule, ImplId, ItemContainerId, - ModuleId, StaticId, StructId, TraitAliasId, TraitId, TypeAliasId, UnionId, VariantId, + ConstId, EnumId, EnumVariantId, EnumVariantLoc, ExternBlockId, FunctionId, HasModule, ImplId, + ItemContainerId, ModuleId, StaticId, StructId, TraitAliasId, TraitId, TypeAliasId, UnionId, + VariantId, + attr::Attrs, db::DefDatabase, expr_store::{ ExpressionStore, ExpressionStoreSourceMap, @@ -28,15 +32,17 @@ use crate::{ }, }, hir::{ExprId, PatId, generics::GenericParams}, - item_tree::{ - AttrOwner, Field, FieldParent, FieldsShape, FileItemTreeId, ItemTree, ItemTreeId, ModItem, - RawVisibility, RawVisibilityId, - }, + item_tree::{FieldsShape, RawVisibility, visibility_from_ast}, lang_item::LangItem, src::HasSource, type_ref::{TraitRef, TypeBound, TypeRefId}, }; +#[inline] +fn as_name_opt(name: Option) -> 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 3867f39b8b..aa373a27b0 100644 --- a/crates/hir-def/src/src.rs +++ b/crates/hir-def/src/src.rs @@ -1,15 +1,13 @@ //! Utilities for mapping between hir IDs and the surface syntax. use either::Either; -use hir_expand::InFile; -use la_arena::ArenaMap; +use hir_expand::{AstId, InFile}; +use la_arena::{Arena, ArenaMap, Idx}; use syntax::{AstNode, AstPtr, ast}; use crate::{ - GenericDefId, ItemTreeLoc, LocalFieldId, LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, - UseId, VariantId, - db::DefDatabase, - item_tree::{AttrOwner, FieldParent, ItemTreeNode}, + AstIdLoc, GenericDefId, LocalFieldId, LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, + UseId, VariantId, attr::Attrs, db::DefDatabase, }; pub trait HasSource { @@ -23,18 +21,13 @@ pub trait HasSource { impl 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 3c67ee9fe5..14d67ea804 100644 --- a/crates/hir-def/src/visibility.rs +++ b/crates/hir-def/src/visibility.rs @@ -2,16 +2,18 @@ use std::iter; -use hir_expand::Lookup; +use hir_expand::{InFile, Lookup}; use la_arena::ArenaMap; +use syntax::ast::{self, HasVisibility}; use triomphe::Arc; use crate::{ - ConstId, FunctionId, HasModule, ItemContainerId, ItemLoc, ItemTreeLoc, LocalFieldId, - LocalModuleId, ModuleId, TraitId, TypeAliasId, VariantId, + ConstId, FunctionId, HasModule, ItemContainerId, LocalFieldId, LocalModuleId, ModuleId, + TraitId, TypeAliasId, VariantId, db::DefDatabase, nameres::DefMap, resolver::{HasResolver, Resolver}, + src::HasSource, }; pub use crate::item_tree::{RawVisibility, VisibilityExplicitness}; @@ -217,49 +219,69 @@ pub(crate) fn field_visibilities_query( for (field_id, field_data) in fields.iter() { res.insert(field_id, Visibility::resolve(db, &resolver, &field_data.visibility)); } + res.shrink_to_fit(); Arc::new(res) } +pub fn visibility_from_ast( + db: &dyn DefDatabase, + resolver: &Resolver<'_>, + ast_vis: InFile>, +) -> Visibility { + let mut span_map = None; + let raw_vis = crate::item_tree::visibility_from_ast(db, ast_vis.value, &mut |range| { + span_map.get_or_insert_with(|| db.span_map(ast_vis.file_id)).span_for_range(range).ctx + }); + Visibility::resolve(db, resolver, &raw_vis) +} + +fn trait_item_visibility( + db: &dyn DefDatabase, + resolver: &Resolver<'_>, + container: ItemContainerId, +) -> Option { + match container { + ItemContainerId::TraitId(trait_) => Some(trait_visibility(db, resolver, trait_)), + _ => None, + } +} + /// Resolve visibility of a function. pub(crate) fn function_visibility_query(db: &dyn DefDatabase, def: FunctionId) -> Visibility { - let resolver = def.resolver(db); let loc = def.lookup(db); - let tree = loc.item_tree_id().item_tree(db); - if let ItemContainerId::TraitId(trait_id) = loc.container { - trait_vis(db, &resolver, trait_id) - } else { - Visibility::resolve(db, &resolver, &tree[tree[loc.id.value].visibility]) - } + let resolver = def.resolver(db); + trait_item_visibility(db, &resolver, loc.container).unwrap_or_else(|| { + let source = loc.source(db); + visibility_from_ast(db, &resolver, source.map(|src| src.visibility())) + }) } /// Resolve visibility of a const. pub(crate) fn const_visibility_query(db: &dyn DefDatabase, def: ConstId) -> Visibility { - let resolver = def.resolver(db); let loc = def.lookup(db); - let tree = loc.item_tree_id().item_tree(db); - if let ItemContainerId::TraitId(trait_id) = loc.container { - trait_vis(db, &resolver, trait_id) - } else { - Visibility::resolve(db, &resolver, &tree[tree[loc.id.value].visibility]) - } + let resolver = def.resolver(db); + trait_item_visibility(db, &resolver, loc.container).unwrap_or_else(|| { + let source = loc.source(db); + visibility_from_ast(db, &resolver, source.map(|src| src.visibility())) + }) } /// Resolve visibility of a type alias. pub(crate) fn type_alias_visibility_query(db: &dyn DefDatabase, def: TypeAliasId) -> Visibility { - let resolver = def.resolver(db); let loc = def.lookup(db); - let tree = loc.item_tree_id().item_tree(db); - if let ItemContainerId::TraitId(trait_id) = loc.container { - trait_vis(db, &resolver, trait_id) - } else { - Visibility::resolve(db, &resolver, &tree[tree[loc.id.value].visibility]) - } + let resolver = def.resolver(db); + trait_item_visibility(db, &resolver, loc.container).unwrap_or_else(|| { + let source = loc.source(db); + visibility_from_ast(db, &resolver, source.map(|src| src.visibility())) + }) } -#[inline] -fn trait_vis(db: &dyn DefDatabase, resolver: &Resolver<'_>, trait_id: TraitId) -> Visibility { - let ItemLoc { id: tree_id, .. } = trait_id.lookup(db); - let item_tree = tree_id.item_tree(db); - let tr_def = &item_tree[tree_id.value]; - Visibility::resolve(db, resolver, &item_tree[tr_def.visibility]) +pub(crate) fn trait_visibility( + db: &dyn DefDatabase, + resolver: &Resolver<'_>, + def: TraitId, +) -> Visibility { + let loc = def.lookup(db); + let source = loc.source(db); + visibility_from_ast(db, resolver, source.map(|src| src.visibility())) } diff --git a/crates/hir-expand/src/files.rs b/crates/hir-expand/src/files.rs index e8f6b82434..a73a22370d 100644 --- a/crates/hir-expand/src/files.rs +++ b/crates/hir-expand/src/files.rs @@ -2,7 +2,7 @@ use std::borrow::Borrow; use either::Either; -use span::{ErasedFileAstId, FileAstId, FileId, SyntaxContext}; +use span::{AstIdNode, ErasedFileAstId, FileAstId, FileId, SyntaxContext}; use syntax::{AstNode, AstPtr, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange, TextSize}; use crate::{ @@ -122,6 +122,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 22b96b55cb..710ac6e542 100644 --- a/crates/hir-ty/src/chalk_db.rs +++ b/crates/hir-ty/src/chalk_db.rs @@ -817,7 +817,7 @@ pub(crate) fn adt_datum_query( .enum_variants(id) .variants .iter() - .map(|&(variant_id, _)| variant_id_to_fields(variant_id.into())) + .map(|&(variant_id, _, _)| variant_id_to_fields(variant_id.into())) .collect(); (rust_ir::AdtKind::Enum, variants) } diff --git a/crates/hir-ty/src/diagnostics/decl_check.rs b/crates/hir-ty/src/diagnostics/decl_check.rs index 099100a732..fae129fddb 100644 --- a/crates/hir-ty/src/diagnostics/decl_check.rs +++ b/crates/hir-ty/src/diagnostics/decl_check.rs @@ -397,7 +397,7 @@ impl<'a> DeclValidator<'a> { fn validate_enum_variants(&mut self, enum_id: EnumId) { let data = self.db.enum_variants(enum_id); - for (variant_id, _) in data.variants.iter() { + for (variant_id, _, _) in data.variants.iter() { self.validate_enum_variant_fields(*variant_id); } @@ -405,7 +405,7 @@ impl<'a> DeclValidator<'a> { let mut enum_variants_replacements = data .variants .iter() - .filter_map(|(_, name)| { + .filter_map(|(_, name, _)| { to_camel_case(&name.display_no_db(edition).to_smolstr()).map(|new_name| { Replacement { current_name: name.clone(), diff --git a/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs b/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs index dd82a0f45c..0914b5aac5 100644 --- a/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs +++ b/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs @@ -465,7 +465,7 @@ impl PatCx for MatchCheckCtx<'_> { ConstructorSet::NoConstructors } else { let mut variants = IndexVec::with_capacity(enum_data.variants.len()); - for &(variant, _) in enum_data.variants.iter() { + for &(variant, _, _) in enum_data.variants.iter() { let is_uninhabited = is_enum_variant_uninhabited_from( cx.db, variant, diff --git a/crates/hir-ty/src/drop.rs b/crates/hir-ty/src/drop.rs index 70763759ef..b9b0f98286 100644 --- a/crates/hir-ty/src/drop.rs +++ b/crates/hir-ty/src/drop.rs @@ -71,7 +71,7 @@ pub(crate) fn has_drop_glue(db: &dyn HirDatabase, ty: Ty, env: Arc { AdtId::EnumId(e) => { let enum_data = self.db.enum_variants(e); - for &(variant, _) in enum_data.variants.iter() { + for &(variant, _, _) in enum_data.variants.iter() { let variant_inhabitedness = self.visit_variant(variant.into(), subst); match variant_inhabitedness { Break(VisiblyUninhabited) => (), diff --git a/crates/hir-ty/src/layout/adt.rs b/crates/hir-ty/src/layout/adt.rs index 3a020bf050..a886c33d15 100644 --- a/crates/hir-ty/src/layout/adt.rs +++ b/crates/hir-ty/src/layout/adt.rs @@ -60,7 +60,7 @@ pub fn layout_of_adt_query( let r = variants .variants .iter() - .map(|&(v, _)| handle_variant(v.into(), &db.variant_fields(v.into()))) + .map(|&(v, _, _)| handle_variant(v.into(), &db.variant_fields(v.into()))) .collect::, _>>()?; (r, db.enum_signature(e).repr.unwrap_or_default(), false) } diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs index 21e5428520..8fb8d64779 100644 --- a/crates/hir-ty/src/mir/eval.rs +++ b/crates/hir-ty/src/mir/eval.rs @@ -2771,12 +2771,15 @@ impl Evaluator<'_> { Err(e) => { let db = self.db; let loc = variant.lookup(db); - let enum_loc = loc.parent.lookup(db); let edition = self.crate_id.data(self.db).edition; let name = format!( "{}::{}", - enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db, edition), - loc.id.item_tree(db)[loc.id.value].name.display(db, edition), + self.db.enum_signature(loc.parent).name.display(db, edition), + self.db + .enum_variants(loc.parent) + .variant_name_by_id(variant) + .unwrap() + .display(db, edition), ); Err(MirEvalError::ConstEvalError(name, Box::new(e))) } diff --git a/crates/hir-ty/src/mir/eval/shim.rs b/crates/hir-ty/src/mir/eval/shim.rs index 90c52ee96f..512a275aa7 100644 --- a/crates/hir-ty/src/mir/eval/shim.rs +++ b/crates/hir-ty/src/mir/eval/shim.rs @@ -65,9 +65,7 @@ impl Evaluator<'_> { Some(abi) => *abi == sym::rust_dash_intrinsic, None => match def.lookup(self.db).container { hir_def::ItemContainerId::ExternBlockId(block) => { - let id = block.lookup(self.db).id; - id.item_tree(self.db)[id.value].abi.as_ref() - == Some(&sym::rust_dash_intrinsic) + self.db.extern_block_abi(block) == Some(sym::rust_dash_intrinsic) } _ => false, }, @@ -87,8 +85,7 @@ impl Evaluator<'_> { } let is_extern_c = match def.lookup(self.db).container { hir_def::ItemContainerId::ExternBlockId(block) => { - let id = block.lookup(self.db).id; - id.item_tree(self.db)[id.value].abi.as_ref() == Some(&sym::C) + self.db.extern_block_abi(block) == Some(sym::C) } _ => false, }; diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs index 99d9351530..ef1f215500 100644 --- a/crates/hir-ty/src/mir/lower.rs +++ b/crates/hir-ty/src/mir/lower.rs @@ -1922,11 +1922,14 @@ impl<'ctx> MirLowerCtx<'ctx> { let edition = self.edition(); let db = self.db; let loc = variant.lookup(db); - let enum_loc = loc.parent.lookup(db); let name = format!( "{}::{}", - enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db, edition), - loc.id.item_tree(db)[loc.id.value].name.display(db, edition), + self.db.enum_signature(loc.parent).name.display(db, edition), + self.db + .enum_variants(loc.parent) + .variant_name_by_id(variant) + .unwrap() + .display(db, edition), ); Err(MirLowerError::ConstEvalError(name.into(), Box::new(e))) } diff --git a/crates/hir-ty/src/mir/pretty.rs b/crates/hir-ty/src/mir/pretty.rs index 7ae6e907e7..91dc2627d1 100644 --- a/crates/hir-ty/src/mir/pretty.rs +++ b/crates/hir-ty/src/mir/pretty.rs @@ -63,16 +63,15 @@ impl MirBody { } hir_def::DefWithBodyId::VariantId(id) => { let loc = id.lookup(db); - let enum_loc = loc.parent.lookup(db); + let edition = this.display_target.edition; w!( this, "enum {}::{} = ", - enum_loc.id.item_tree(db)[enum_loc.id.value] - .name - .display(db, this.display_target.edition), - loc.id.item_tree(db)[loc.id.value] - .name - .display(db, this.display_target.edition), + db.enum_signature(loc.parent).name.display(db, edition), + db.enum_variants(loc.parent) + .variant_name_by_id(id) + .unwrap() + .display(db, edition), ) } }); diff --git a/crates/hir-ty/src/tests.rs b/crates/hir-ty/src/tests.rs index 2b75bd6f16..48af7b2e32 100644 --- a/crates/hir-ty/src/tests.rs +++ b/crates/hir-ty/src/tests.rs @@ -479,7 +479,7 @@ pub(crate) fn visit_module( visit_body(db, &body, cb); } ModuleDefId::AdtId(hir_def::AdtId::EnumId(it)) => { - db.enum_variants(it).variants.iter().for_each(|&(it, _)| { + db.enum_variants(it).variants.iter().for_each(|&(it, _, _)| { let body = db.body(it.into()); cb(it.into()); visit_body(db, &body, cb); diff --git a/crates/hir-ty/src/tests/incremental.rs b/crates/hir-ty/src/tests/incremental.rs index 6ac260ac76..a055ef879d 100644 --- a/crates/hir-ty/src/tests/incremental.rs +++ b/crates/hir-ty/src/tests/incremental.rs @@ -353,6 +353,7 @@ impl SomeStruct { "impl_self_ty_with_diagnostics_shim".to_owned(), "struct_signature_shim".to_owned(), "struct_signature_with_source_map_shim".to_owned(), + "attrs_shim".to_owned(), "type_for_adt_tracked".to_owned(), ]; @@ -442,6 +443,6 @@ fn main() { let _inference_result = db.infer(def); } }); - assert!(format!("{events:?}").contains("trait_solve_shim")) + assert!(!format!("{events:?}").contains("trait_solve_shim")) } } diff --git a/crates/hir-ty/src/utils.rs b/crates/hir-ty/src/utils.rs index 1e0ff423de..f797e60b05 100644 --- a/crates/hir-ty/src/utils.rs +++ b/crates/hir-ty/src/utils.rs @@ -293,9 +293,7 @@ pub fn is_fn_unsafe_to_call( let loc = func.lookup(db); match loc.container { hir_def::ItemContainerId::ExternBlockId(block) => { - let id = block.lookup(db).id; - let is_intrinsic_block = - id.item_tree(db)[id.value].abi.as_ref() == Some(&sym::rust_dash_intrinsic); + let is_intrinsic_block = db.extern_block_abi(block) == Some(sym::rust_dash_intrinsic); if is_intrinsic_block { // legacy intrinsics // extern "rust-intrinsic" intrinsics are unsafe unless they have the rustc_safe_intrinsic attribute diff --git a/crates/hir-ty/src/variance.rs b/crates/hir-ty/src/variance.rs index d6b43aeed4..62478d4fd8 100644 --- a/crates/hir-ty/src/variance.rs +++ b/crates/hir-ty/src/variance.rs @@ -213,7 +213,7 @@ impl Context<'_> { AdtId::StructId(s) => add_constraints_from_variant(VariantId::StructId(s)), AdtId::UnionId(u) => add_constraints_from_variant(VariantId::UnionId(u)), AdtId::EnumId(e) => { - db.enum_variants(e).variants.iter().for_each(|&(variant, _)| { + db.enum_variants(e).variants.iter().for_each(|&(variant, _, _)| { add_constraints_from_variant(VariantId::EnumVariantId(variant)) }); } diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 969fd3eb48..c746b88c5b 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -52,12 +52,14 @@ use hir_def::{ BindingAnnotation, BindingId, Expr, ExprId, ExprOrPatId, LabelId, Pat, generics::{LifetimeParamData, TypeOrConstParamData, TypeParamProvenance}, }, - item_tree::{AttrOwner, FieldParent, ImportAlias, ItemTreeFieldId, ItemTreeNode}, + item_tree::ImportAlias, layout::{self, ReprOptions, TargetDataLayout}, nameres::{self, diagnostics::DefDiagnostic}, per_ns::PerNs, resolver::{HasResolver, Resolver}, signatures::{ImplFlags, StaticFlags, TraitFlags, VariantFields}, + src::HasSource as _, + visibility::visibility_from_ast, }; use hir_expand::{ AstId, MacroCallKind, RenderedExpandError, ValueResult, attrs::collect_attrs, @@ -81,11 +83,11 @@ use itertools::Itertools; use nameres::diagnostics::DefDiagnosticKind; use rustc_hash::FxHashSet; use smallvec::SmallVec; -use span::{Edition, FileId}; +use span::{AstIdNode, Edition, FileId}; use stdx::{format_to, impl_from, never}; use syntax::{ AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, T, TextRange, ToSmolStr, - ast::{self, HasAttrs as _, HasName}, + ast::{self, HasAttrs as _, HasName, HasVisibility as _}, format_smolstr, }; use triomphe::{Arc, ThinArc}; @@ -687,7 +689,7 @@ impl Module { let source_map = db.enum_signature_with_source_map(e.id).1; expr_store_diagnostics(db, acc, &source_map); let (variants, diagnostics) = db.enum_variants_with_diagnostics(e.id); - let file = e.id.lookup(db).id.file_id(); + let file = e.id.lookup(db).id.file_id; let ast_id_map = db.ast_id_map(file); if let Some(diagnostics) = &diagnostics { for diag in diagnostics.iter() { @@ -704,7 +706,7 @@ impl Module { ); } } - for &(v, _) in &variants.variants { + for &(v, _, _) in &variants.variants { let source_map = db.variant_fields_with_source_map(v.into()).1; push_ty_diagnostics( db, @@ -742,12 +744,10 @@ impl Module { GenericDef::Impl(impl_def).diagnostics(db, acc); let loc = impl_def.id.lookup(db); - let tree = loc.id.item_tree(db); let source_map = db.impl_signature_with_source_map(impl_def.id).1; expr_store_diagnostics(db, acc, &source_map); - let node = &tree[loc.id.value]; - let file_id = loc.id.file_id(); + let file_id = loc.id.file_id; if file_id.macro_file().is_some_and(|it| it.kind(db) == MacroKind::DeriveBuiltIn) { // these expansion come from us, diagnosing them is a waste of resources // FIXME: Once we diagnose the inputs to builtin derives, we should at least extract those diagnostics somehow @@ -765,11 +765,11 @@ impl Module { } if inherent_impls.invalid_impls().contains(&impl_def.id) { - acc.push(IncoherentImpl { impl_: ast_id_map.get(node.ast_id()), file_id }.into()) + acc.push(IncoherentImpl { impl_: ast_id_map.get(loc.id.value), file_id }.into()) } if !impl_def.check_orphan_rules(db) { - acc.push(TraitImplOrphan { impl_: ast_id_map.get(node.ast_id()), file_id }.into()) + acc.push(TraitImplOrphan { impl_: ast_id_map.get(loc.id.value), file_id }.into()) } let trait_ = impl_def.trait_(db); @@ -808,11 +808,11 @@ impl Module { // unsafe negative impl (true, _, true, _) | // unsafe impl for safe trait - (true, false, _, false) => acc.push(TraitImplIncorrectSafety { impl_: ast_id_map.get(node.ast_id()), file_id, should_be_safe: true }.into()), + (true, false, _, false) => acc.push(TraitImplIncorrectSafety { impl_: ast_id_map.get(loc.id.value), file_id, should_be_safe: true }.into()), // safe impl for unsafe trait (false, true, false, _) | // safe impl of dangling drop - (false, false, _, true) => acc.push(TraitImplIncorrectSafety { impl_: ast_id_map.get(node.ast_id()), file_id, should_be_safe: false }.into()), + (false, false, _, true) => acc.push(TraitImplIncorrectSafety { impl_: ast_id_map.get(loc.id.value), file_id, should_be_safe: false }.into()), _ => (), }; @@ -839,7 +839,7 @@ impl Module { TraitImplRedundantAssocItems { trait_, file_id, - impl_: ast_id_map.get(node.ast_id()), + impl_: ast_id_map.get(loc.id.value), assoc_item: (name, assoc_item), } .into(), @@ -889,7 +889,7 @@ impl Module { if !missing.is_empty() { acc.push( TraitImplMissingAssocItems { - impl_: ast_id_map.get(node.ast_id()), + impl_: ast_id_map.get(loc.id.value), file_id, missing, } @@ -1076,73 +1076,25 @@ fn emit_def_diagnostic_( ) } DefDiagnosticKind::UnresolvedImport { id, index } => { - let file_id = id.file_id(); - let item_tree = id.item_tree(db); - let import = &item_tree[id.value]; + let file_id = id.file_id; - let use_tree = import.use_tree_to_ast(db, file_id, *index); + let use_tree = hir_def::src::use_tree_to_ast(db, *id, *index); acc.push( UnresolvedImport { decl: InFile::new(file_id, AstPtr::new(&use_tree)) }.into(), ); } - DefDiagnosticKind::UnconfiguredCode { tree, item, cfg, opts } => { - let item_tree = tree.item_tree(db); - let ast_id_map = db.ast_id_map(tree.file_id()); - // FIXME: This parses... We could probably store relative ranges for the children things - // here in the item tree? - (|| { - let process_field_list = - |field_list: Option<_>, idx: ItemTreeFieldId| match field_list? { - ast::FieldList::RecordFieldList(it) => Some(SyntaxNodePtr::new( - it.fields().nth(idx.into_raw().into_u32() as usize)?.syntax(), - )), - ast::FieldList::TupleFieldList(it) => Some(SyntaxNodePtr::new( - it.fields().nth(idx.into_raw().into_u32() as usize)?.syntax(), - )), - }; - let ptr = match *item { - AttrOwner::ModItem(it) => { - ast_id_map.get(it.ast_id(&item_tree)).syntax_node_ptr() - } - AttrOwner::TopLevel => ast_id_map.root(), - AttrOwner::Variant(it) => { - ast_id_map.get(item_tree[it].ast_id).syntax_node_ptr() - } - AttrOwner::Field(FieldParent::EnumVariant(parent), idx) => process_field_list( - ast_id_map - .get(item_tree[parent].ast_id) - .to_node(&db.parse_or_expand(tree.file_id())) - .field_list(), - idx, - )?, - AttrOwner::Field(FieldParent::Struct(parent), idx) => process_field_list( - ast_id_map - .get(item_tree[parent.index()].ast_id) - .to_node(&db.parse_or_expand(tree.file_id())) - .field_list(), - idx, - )?, - AttrOwner::Field(FieldParent::Union(parent), idx) => SyntaxNodePtr::new( - ast_id_map - .get(item_tree[parent.index()].ast_id) - .to_node(&db.parse_or_expand(tree.file_id())) - .record_field_list()? - .fields() - .nth(idx.into_raw().into_u32() as usize)? - .syntax(), - ), - }; - acc.push( - InactiveCode { - node: InFile::new(tree.file_id(), ptr), - cfg: cfg.clone(), - opts: opts.clone(), - } - .into(), - ); - Some(()) - })(); + DefDiagnosticKind::UnconfiguredCode { ast_id, cfg, opts } => { + let ast_id_map = db.ast_id_map(ast_id.file_id); + let ptr = ast_id_map.get_erased(ast_id.value); + acc.push( + InactiveCode { + node: InFile::new(ast_id.file_id, ptr), + cfg: cfg.clone(), + opts: opts.clone(), + } + .into(), + ); } DefDiagnosticKind::UnresolvedMacroCall { ast, path } => { let (node, precise_location) = precise_macro_call_location(ast, db); @@ -1478,12 +1430,8 @@ impl Struct { impl HasVisibility for Struct { fn visibility(&self, db: &dyn HirDatabase) -> Visibility { let loc = self.id.lookup(db); - let item_tree = loc.id.item_tree(db); - Visibility::resolve( - db, - &self.id.resolver(db), - &item_tree[item_tree[loc.id.value].visibility], - ) + let source = loc.source(db); + visibility_from_ast(db, &self.id.resolver(db), source.map(|src| src.visibility())) } } @@ -1536,12 +1484,8 @@ impl Union { impl HasVisibility for Union { fn visibility(&self, db: &dyn HirDatabase) -> Visibility { let loc = self.id.lookup(db); - let item_tree = loc.id.item_tree(db); - Visibility::resolve( - db, - &self.id.resolver(db), - &item_tree[item_tree[loc.id.value].visibility], - ) + let source = loc.source(db); + visibility_from_ast(db, &self.id.resolver(db), source.map(|src| src.visibility())) } } @@ -1560,7 +1504,7 @@ impl Enum { } pub fn variants(self, db: &dyn HirDatabase) -> Vec { - db.enum_variants(self.id).variants.iter().map(|&(id, _)| Variant { id }).collect() + db.enum_variants(self.id).variants.iter().map(|&(id, _, _)| Variant { id }).collect() } pub fn num_variants(self, db: &dyn HirDatabase) -> usize { @@ -1629,12 +1573,8 @@ impl Enum { impl HasVisibility for Enum { fn visibility(&self, db: &dyn HirDatabase) -> Visibility { let loc = self.id.lookup(db); - let item_tree = loc.id.item_tree(db); - Visibility::resolve( - db, - &self.id.resolver(db), - &item_tree[item_tree[loc.id.value].visibility], - ) + let source = loc.source(db); + visibility_from_ast(db, &self.id.resolver(db), source.map(|src| src.visibility())) } } @@ -2708,10 +2648,9 @@ impl ExternCrateDecl { pub fn resolved_crate(self, db: &dyn HirDatabase) -> Option { let loc = self.id.lookup(db); - let item_tree = loc.id.item_tree(db); let krate = loc.container.krate(); - let name = &item_tree[loc.id.value].name; - if *name == sym::self_ { + let name = self.name(db); + if name == sym::self_ { Some(krate.into()) } else { krate.data(db).dependencies.iter().find_map(|dep| { @@ -2722,25 +2661,29 @@ impl ExternCrateDecl { pub fn name(self, db: &dyn HirDatabase) -> Name { let loc = self.id.lookup(db); - let item_tree = loc.id.item_tree(db); - item_tree[loc.id.value].name.clone() + let source = loc.source(db); + as_name_opt(source.value.name_ref()) } pub fn alias(self, db: &dyn HirDatabase) -> Option { 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)), } } } @@ -2748,12 +2691,8 @@ impl ExternCrateDecl { impl HasVisibility for ExternCrateDecl { fn visibility(&self, db: &dyn HirDatabase) -> Visibility { let loc = self.id.lookup(db); - let item_tree = loc.id.item_tree(db); - Visibility::resolve( - db, - &self.id.resolver(db), - &item_tree[item_tree[loc.id.value].visibility], - ) + let source = loc.source(db); + visibility_from_ast(db, &self.id.resolver(db), source.map(|src| src.visibility())) } } @@ -2873,12 +2812,8 @@ impl Static { impl HasVisibility for Static { fn visibility(&self, db: &dyn HirDatabase) -> Visibility { let loc = self.id.lookup(db); - let item_tree = loc.id.item_tree(db); - Visibility::resolve( - db, - &self.id.resolver(db), - &item_tree[item_tree[loc.id.value].visibility], - ) + let source = loc.source(db); + visibility_from_ast(db, &self.id.resolver(db), source.map(|src| src.visibility())) } } @@ -2967,11 +2902,7 @@ impl Trait { } fn all_macro_calls(&self, db: &dyn HirDatabase) -> Box<[(AstId, MacroCallId)]> { - db.trait_items(self.id) - .macro_calls - .as_ref() - .map(|it| it.as_ref().clone().into_boxed_slice()) - .unwrap_or_default() + db.trait_items(self.id).macro_calls.to_vec().into_boxed_slice() } /// `#[rust_analyzer::completions(...)]` mode. @@ -2983,12 +2914,8 @@ impl Trait { impl HasVisibility for Trait { fn visibility(&self, db: &dyn HirDatabase) -> Visibility { let loc = self.id.lookup(db); - let item_tree = loc.id.item_tree(db); - Visibility::resolve( - db, - &self.id.resolver(db), - &item_tree[item_tree[loc.id.value].visibility], - ) + let source = loc.source(db); + visibility_from_ast(db, &self.id.resolver(db), source.map(|src| src.visibility())) } } @@ -3010,12 +2937,8 @@ impl TraitAlias { impl HasVisibility for TraitAlias { fn visibility(&self, db: &dyn HirDatabase) -> Visibility { let loc = self.id.lookup(db); - let item_tree = loc.id.item_tree(db); - Visibility::resolve( - db, - &self.id.resolver(db), - &item_tree[item_tree[loc.id.value].visibility], - ) + let source = loc.source(db); + visibility_from_ast(db, &self.id.resolver(db), source.map(|src| src.visibility())) } } @@ -3163,25 +3086,23 @@ impl Macro { match self.id { MacroId::Macro2Id(id) => { let loc = id.lookup(db); - let item_tree = loc.id.item_tree(db); - item_tree[loc.id.value].name.clone() + let source = loc.source(db); + as_name_opt(source.value.name()) } MacroId::MacroRulesId(id) => { let loc = id.lookup(db); - let item_tree = loc.id.item_tree(db); - item_tree[loc.id.value].name.clone() + let source = loc.source(db); + as_name_opt(source.value.name()) } MacroId::ProcMacroId(id) => { let loc = id.lookup(db); - let item_tree = loc.id.item_tree(db); + let source = loc.source(db); match loc.kind { ProcMacroKind::CustomDerive => db .attrs(id.into()) .parse_proc_macro_derive() - .map_or_else(|| item_tree[loc.id.value].name.clone(), |(it, _)| it), - ProcMacroKind::Bang | ProcMacroKind::Attr => { - item_tree[loc.id.value].name.clone() - } + .map_or_else(|| as_name_opt(source.value.name()), |(it, _)| it), + ProcMacroKind::Bang | ProcMacroKind::Attr => as_name_opt(source.value.name()), } } } @@ -3278,12 +3199,8 @@ impl HasVisibility for Macro { match self.id { MacroId::Macro2Id(id) => { let loc = id.lookup(db); - let item_tree = loc.id.item_tree(db); - Visibility::resolve( - db, - &id.resolver(db), - &item_tree[item_tree[loc.id.value].visibility], - ) + let source = loc.source(db); + visibility_from_ast(db, &id.resolver(db), source.map(|src| src.visibility())) } MacroId::MacroRulesId(_) => Visibility::Public, MacroId::ProcMacroId(_) => Visibility::Public, @@ -3437,7 +3354,7 @@ fn as_assoc_item<'db, ID, DEF, LOC>( where ID: Lookup>, DEF: From, - LOC: ItemTreeNode, + LOC: AstIdNode, { match id.lookup(db).container { ItemContainerId::TraitId(_) | ItemContainerId::ImplId(_) => Some(ctor(DEF::from(id))), @@ -3453,7 +3370,7 @@ fn as_extern_assoc_item<'db, ID, DEF, LOC>( where ID: Lookup>, DEF: From, - LOC: ItemTreeNode, + LOC: AstIdNode, { match id.lookup(db).container { ItemContainerId::ExternBlockId(_) => Some(ctor(DEF::from(id))), @@ -4545,11 +4462,7 @@ impl Impl { } fn all_macro_calls(&self, db: &dyn HirDatabase) -> Box<[(AstId, MacroCallId)]> { - db.impl_items(self.id) - .macro_calls - .as_ref() - .map(|it| it.as_ref().clone().into_boxed_slice()) - .unwrap_or_default() + db.impl_items(self.id).macro_calls.to_vec().into_boxed_slice() } } @@ -6510,3 +6423,7 @@ pub fn resolve_absolute_path<'a, I: Iterator + 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 1a6d63c88c..ea44451a8e 100644 --- a/crates/hir/src/semantics/child_by_source.rs +++ b/crates/hir/src/semantics/child_by_source.rs @@ -6,10 +6,11 @@ use either::Either; use hir_expand::{HirFileId, attrs::collect_attrs}; +use span::AstIdNode; use syntax::{AstPtr, ast}; use hir_def::{ - AdtId, AssocItemId, DefWithBodyId, EnumId, FieldId, GenericDefId, ImplId, ItemTreeLoc, + AdtId, AssocItemId, AstIdLoc, DefWithBodyId, EnumId, FieldId, GenericDefId, ImplId, LifetimeParamId, Lookup, MacroId, ModuleDefId, ModuleId, TraitId, TypeOrConstParamId, VariantId, db::DefDatabase, @@ -19,7 +20,6 @@ use hir_def::{ }, hir::generics::GenericParams, item_scope::ItemScope, - item_tree::ItemTreeNode, nameres::DefMap, src::{HasChildSource, HasSource}, }; @@ -113,7 +113,7 @@ impl ChildBySource for ItemScope { ids.iter().for_each(|&id| { if let MacroId::MacroRulesId(id) = id { let loc = id.lookup(db); - if loc.id.file_id() == file_id { + if loc.id.file_id == file_id { res[keys::MACRO_RULES].insert(loc.ast_ptr(db).value, id); } } @@ -199,16 +199,14 @@ impl ChildBySource for VariantId { impl ChildBySource for EnumId { fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) { let loc = &self.lookup(db); - if file_id != loc.id.file_id() { + if file_id != loc.id.file_id { return; } - let tree = loc.id.item_tree(db); - let ast_id_map = db.ast_id_map(loc.id.file_id()); + let ast_id_map = db.ast_id_map(loc.id.file_id); - db.enum_variants(*self).variants.iter().for_each(|&(variant, _)| { - res[keys::ENUM_VARIANT] - .insert(ast_id_map.get(tree[variant.lookup(db).id.value].ast_id), variant); + db.enum_variants(*self).variants.iter().for_each(|&(variant, _, _)| { + res[keys::ENUM_VARIANT].insert(ast_id_map.get(variant.lookup(db).id.value), variant); }); let (_, source_map) = db.enum_signature_with_source_map(*self); source_map @@ -287,15 +285,14 @@ fn insert_item_loc( 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) } } From 0a1a78cb879c35217b9f97f1a104b4b053adca9e Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Wed, 21 May 2025 13:42:48 +0300 Subject: [PATCH 12/56] Remove most of the item tree I'm joking, but now that the def map is the only thing that uses the item tree, we can remove a lot of things from it that aren't needed for the def map. --- crates/hir-def/src/item_tree.rs | 158 +------------------- crates/hir-def/src/item_tree/lower.rs | 196 +++---------------------- crates/hir-def/src/item_tree/pretty.rs | 96 +++--------- crates/hir-def/src/item_tree/tests.rs | 45 +----- 4 files changed, 52 insertions(+), 443 deletions(-) diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs index 65dc35337a..07d1500fc0 100644 --- a/crates/hir-def/src/item_tree.rs +++ b/crates/hir-def/src/item_tree.rs @@ -29,7 +29,6 @@ //! //! In general, any item in the `ItemTree` stores its `AstId`, which allows mapping it back to its //! surface syntax. -#![allow(unexpected_cfgs)] mod lower; mod pretty; @@ -51,7 +50,7 @@ use hir_expand::{ 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; @@ -237,7 +236,6 @@ impl ItemTree { structs, unions, enums, - variants, consts, statics, traits, @@ -258,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(); @@ -310,7 +307,6 @@ struct ItemTreeData { structs: Arena, unions: Arena, enums: Arena, - variants: Arena, consts: Arena, statics: Arena, traits: Arena, @@ -340,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; @@ -383,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); @@ -547,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 { @@ -624,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, @@ -712,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]>, } @@ -728,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, } @@ -737,7 +684,6 @@ pub struct Struct { pub struct Union { pub name: Name, pub visibility: RawVisibilityId, - pub fields: Box<[Field]>, pub ast_id: FileAstId, } @@ -745,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, @@ -788,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 _: () = ();` @@ -817,7 +744,6 @@ pub struct Static { pub struct Trait { pub name: Name, pub visibility: RawVisibilityId, - pub items: Box<[AssocItem]>, pub ast_id: FileAstId, } @@ -830,7 +756,6 @@ pub struct TraitAlias { #[derive(Debug, Clone, Eq, PartialEq)] pub struct Impl { - pub items: Box<[AssocItem]>, pub ast_id: FileAstId, } @@ -971,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 5776542769..d9588cb487 100644 --- a/crates/hir-def/src/item_tree/lower.rs +++ b/crates/hir-def/src/item_tree/lower.rs @@ -8,23 +8,22 @@ use hir_expand::{ name::AsName, span_map::{SpanMap, SpanMapRef}, }; -use intern::{Symbol, sym}; use la_arena::Arena; use span::{AstIdMap, SyntaxContext}; use syntax::{ AstNode, - ast::{self, HasModuleItem, HasName, IsString}, + ast::{self, HasModuleItem, HasName}, }; use triomphe::Arc; use crate::{ db::DefDatabase, item_tree::{ - AssocItem, AttrOwner, Const, Enum, ExternBlock, ExternCrate, Field, FieldParent, - FieldsShape, FileItemTreeId, Function, Idx, Impl, ImportAlias, Interned, ItemTree, - ItemTreeData, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, ModPath, Name, Range, - RawAttrs, RawIdx, RawVisibility, RawVisibilityId, Static, Struct, StructKind, Trait, - TraitAlias, TypeAlias, Union, Use, UseTree, UseTreeKind, Variant, VisibilityExplicitness, + AttrOwner, Const, Enum, ExternBlock, ExternCrate, FieldsShape, FileItemTreeId, Function, + Idx, Impl, ImportAlias, Interned, ItemTree, ItemTreeData, Macro2, MacroCall, MacroRules, + Mod, ModItem, ModKind, ModPath, RawAttrs, RawVisibility, RawVisibilityId, Static, Struct, + StructKind, Trait, TraitAlias, TypeAlias, Union, Use, UseTree, UseTreeKind, + VisibilityExplicitness, }, }; @@ -163,118 +162,23 @@ impl<'a> Ctx<'a> { } } - fn lower_assoc_item(&mut self, item_node: &ast::AssocItem) -> Option { - 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> { @@ -647,3 +485,11 @@ pub(crate) 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 8ff14751c6..0c62b86dae 100644 --- a/crates/hir-def/src/item_tree/pretty.rs +++ b/crates/hir-def/src/item_tree/pretty.rs @@ -2,15 +2,13 @@ use std::fmt::{self, Write}; -use la_arena::{Idx, RawIdx}; use span::{Edition, ErasedFileAstId}; use crate::{ item_tree::{ - AttrOwner, Const, DefDatabase, Enum, ExternBlock, ExternCrate, Field, FieldParent, - FieldsShape, FileItemTreeId, Function, Impl, ItemTree, Macro2, MacroCall, MacroRules, Mod, - ModItem, ModKind, RawAttrs, RawVisibilityId, Static, Struct, Trait, TraitAlias, TypeAlias, - Union, Use, UseTree, UseTreeKind, Variant, + AttrOwner, Const, DefDatabase, Enum, ExternBlock, ExternCrate, FieldsShape, Function, Impl, + ItemTree, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, RawAttrs, RawVisibilityId, + Static, Struct, Trait, TraitAlias, TypeAlias, Union, Use, UseTree, UseTreeKind, }, visibility::RawVisibility, }; @@ -118,44 +116,14 @@ impl Printer<'_> { }; } - fn print_fields(&mut self, parent: FieldParent, kind: FieldsShape, fields: &[Field]) { - let edition = self.edition; + fn print_fields(&mut self, kind: FieldsShape) { match kind { FieldsShape::Record => { self.whitespace(); - w!(self, "{{"); - self.indented(|this| { - for (idx, Field { name, visibility, is_unsafe }) in fields.iter().enumerate() { - this.print_attrs_of( - AttrOwner::Field(parent, Idx::from_raw(RawIdx::from(idx as u32))), - "\n", - ); - this.print_visibility(*visibility); - if *is_unsafe { - w!(this, "unsafe "); - } - - wln!(this, "{},", name.display(self.db, edition)); - } - }); - w!(self, "}}"); + w!(self, "{{ ... }}"); } FieldsShape::Tuple => { - w!(self, "("); - self.indented(|this| { - for (idx, Field { name, visibility, is_unsafe }) in fields.iter().enumerate() { - this.print_attrs_of( - AttrOwner::Field(parent, Idx::from_raw(RawIdx::from(idx as u32))), - "\n", - ); - this.print_visibility(*visibility); - if *is_unsafe { - w!(this, "unsafe "); - } - wln!(this, "{},", name.display(self.db, edition)); - } - }); - w!(self, ")"); + w!(self, "(...)"); } FieldsShape::Unit => {} } @@ -214,13 +182,9 @@ impl Printer<'_> { wln!(self, ";"); } ModItem::ExternBlock(it) => { - let ExternBlock { abi, ast_id, children } = &self.tree[it]; + let ExternBlock { ast_id, children } = &self.tree[it]; self.print_ast_id(ast_id.erase()); - w!(self, "extern "); - if let Some(abi) = abi { - w!(self, "\"{}\" ", abi); - } - w!(self, "{{"); + w!(self, "extern {{"); self.indented(|this| { for child in &**children { this.print_mod_item(*child); @@ -235,11 +199,11 @@ impl Printer<'_> { wln!(self, "fn {};", name.display(self.db, self.edition)); } ModItem::Struct(it) => { - let Struct { visibility, name, fields, shape: kind, ast_id } = &self.tree[it]; + let Struct { visibility, name, shape: kind, ast_id } = &self.tree[it]; self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); w!(self, "struct {}", name.display(self.db, self.edition)); - self.print_fields(FieldParent::Struct(it), *kind, fields); + self.print_fields(*kind); if matches!(kind, FieldsShape::Record) { wln!(self); } else { @@ -247,30 +211,18 @@ impl Printer<'_> { } } ModItem::Union(it) => { - let Union { name, visibility, fields, ast_id } = &self.tree[it]; + let Union { name, visibility, ast_id } = &self.tree[it]; self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); w!(self, "union {}", name.display(self.db, self.edition)); - self.print_fields(FieldParent::Union(it), FieldsShape::Record, fields); + self.print_fields(FieldsShape::Record); wln!(self); } ModItem::Enum(it) => { - let Enum { name, visibility, variants, ast_id } = &self.tree[it]; + let Enum { name, visibility, ast_id } = &self.tree[it]; self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); - w!(self, "enum {} {{", name.display(self.db, self.edition)); - let edition = self.edition; - self.indented(|this| { - for variant in FileItemTreeId::range_iter(variants.clone()) { - let Variant { name, fields, shape: kind, ast_id } = &this.tree[variant]; - this.print_ast_id(ast_id.erase()); - this.print_attrs_of(variant, "\n"); - w!(this, "{}", name.display(self.db, edition)); - this.print_fields(FieldParent::EnumVariant(variant), *kind, fields); - wln!(this, ","); - } - }); - wln!(self, "}}"); + w!(self, "enum {} {{ ... }}", name.display(self.db, self.edition)); } ModItem::Const(it) => { let Const { name, visibility, ast_id } = &self.tree[it]; @@ -293,16 +245,10 @@ impl Printer<'_> { wln!(self); } ModItem::Trait(it) => { - let Trait { name, visibility, items, ast_id } = &self.tree[it]; + let Trait { name, visibility, ast_id } = &self.tree[it]; self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); - w!(self, "trait {} {{", name.display(self.db, self.edition)); - self.indented(|this| { - for item in &**items { - this.print_mod_item((*item).into()); - } - }); - wln!(self, "}}"); + w!(self, "trait {} {{ ... }}", name.display(self.db, self.edition)); } ModItem::TraitAlias(it) => { let TraitAlias { name, visibility, ast_id } = &self.tree[it]; @@ -311,15 +257,9 @@ impl Printer<'_> { wln!(self, "trait {} = ..;", name.display(self.db, self.edition)); } ModItem::Impl(it) => { - let Impl { items, ast_id } = &self.tree[it]; + let Impl { ast_id } = &self.tree[it]; self.print_ast_id(ast_id.erase()); - w!(self, "impl {{"); - self.indented(|this| { - for item in &**items { - this.print_mod_item((*item).into()); - } - }); - wln!(self, "}}"); + w!(self, "impl {{ ... }}"); } ModItem::TypeAlias(it) => { let TypeAlias { name, visibility, ast_id } = &self.tree[it]; diff --git a/crates/hir-def/src/item_tree/tests.rs b/crates/hir-def/src/item_tree/tests.rs index 7a85e8d175..e39efd31c6 100644 --- a/crates/hir-def/src/item_tree/tests.rs +++ b/crates/hir-def/src/item_tree/tests.rs @@ -73,10 +73,10 @@ extern "C" { fn ex_fn(); } "#, - expect![[r##" + expect![[r#" #[on_extern_block] // AstId: ExternBlock[0000, 0] - extern "C" { + extern { #[on_extern_type] // AstId: TypeAlias[9FDF, 0] pub(self) type ExType; @@ -89,7 +89,7 @@ extern "C" { // AstId: Fn[452D, 0] pub(self) fn ex_fn; } - "##]], + "#]], ); } @@ -129,39 +129,16 @@ enum E { #[derive(Debug)] // AstId: Struct[C7A1, 0] - pub(self) struct Struct { - #[doc = " fld docs"] - pub(self) fld, - } + pub(self) struct Struct { ... } // AstId: Struct[DAC2, 0] - pub(self) struct Tuple( - #[attr] - pub(self) 0, - ); + pub(self) struct Tuple(...); // AstId: Union[2DBB, 0] - pub(self) union Ize { - pub(self) a, - pub(self) b, - } + pub(self) union Ize { ... } // AstId: Enum[7FF8, 0] - pub(self) enum E { - // AstId: Variant[C717, 0] - #[doc = " comment on Unit"] - Unit, - // AstId: Variant[AEAB, 0] - #[doc = " comment on Tuple"] - Tuple( - pub(self) 0, - ), - // AstId: Variant[4B1B, 0] - Struct { - #[doc = " comment on a: u8"] - pub(self) a, - }, - } + pub(self) enum E { ... } "#]], ); } @@ -197,13 +174,7 @@ trait Tr: SuperTrait + 'lifetime { pub(self) fn f; // AstId: Trait[2998, 0] - pub(self) trait Tr { - // AstId: TypeAlias[9F08, 0] - pub(self) type Assoc; - - // AstId: Fn[6C0C, 0] - pub(self) fn method; - } + pub(self) trait Tr { ... } "#]], ); } From 09a66474a231850040af2b3d0fdf92ce16b7c65d Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Wed, 21 May 2025 14:59:21 +0300 Subject: [PATCH 13/56] Ignore ast id hashes in typos check --- .typos.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/.typos.toml b/.typos.toml index e938bddd4b..cdbc003a80 100644 --- a/.typos.toml +++ b/.typos.toml @@ -18,6 +18,7 @@ extend-ignore-re = [ "INOUT", "optin", "=Pn", + "\\[[0-9A-F]{4},", # AstId hex hashes # ignore `// spellchecker:off` until `// spellchecker:on` "(?s)(#|//)\\s*spellchecker:off.*?\\n\\s*(#|//)\\s*spellchecker:on", ] From 9a1063f2663ad5ea24665f2e1f3cabcdb51521f4 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Wed, 21 May 2025 15:24:07 +0300 Subject: [PATCH 14/56] LRU ast id map We can do that and it's pretty heavy. --- crates/hir-expand/src/db.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/hir-expand/src/db.rs b/crates/hir-expand/src/db.rs index 7cb1b6c020..b7df3ee2f9 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(1024)] fn ast_id_map(&self, file_id: HirFileId) -> Arc; #[salsa::transparent] From 13494f4cac0bde07de0c79003dcf5a1aaf81fac3 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 12 Jun 2025 08:52:19 +0200 Subject: [PATCH 15/56] `ItemTree`'s `ItemVisibilities` has no identity, so deduplicate --- crates/base-db/src/input.rs | 4 +--- crates/base-db/src/lib.rs | 2 ++ crates/hir-def/src/expr_store/lower.rs | 3 +-- crates/hir-def/src/item_tree.rs | 31 ++++---------------------- crates/hir-def/src/item_tree/lower.rs | 30 +++++++++++++++++++++++-- crates/hir/src/symbols.rs | 3 +-- crates/ide/src/runnables.rs | 4 ++-- 7 files changed, 39 insertions(+), 38 deletions(-) diff --git a/crates/base-db/src/input.rs b/crates/base-db/src/input.rs index 745238167b..2a87b15248 100644 --- a/crates/base-db/src/input.rs +++ b/crates/base-db/src/input.rs @@ -20,12 +20,10 @@ use span::Edition; use triomphe::Arc; use vfs::{AbsPathBuf, AnchoredPath, FileId, VfsPath, file_set::FileSet}; -use crate::{CrateWorkspaceData, EditionedFileId, RootQueryDb}; +use crate::{CrateWorkspaceData, EditionedFileId, FxIndexSet, RootQueryDb}; pub type ProcMacroPaths = FxHashMap>; -type FxIndexSet = indexmap::IndexSet; - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct SourceRootId(pub u32); diff --git a/crates/base-db/src/lib.rs b/crates/base-db/src/lib.rs index 4d4e6cae03..478fae67c8 100644 --- a/crates/base-db/src/lib.rs +++ b/crates/base-db/src/lib.rs @@ -28,6 +28,8 @@ use syntax::{Parse, SyntaxError, ast}; use triomphe::Arc; pub use vfs::{AnchoredPath, AnchoredPathBuf, FileId, VfsPath, file_set::FileSet}; +pub type FxIndexSet = indexmap::IndexSet; + #[macro_export] macro_rules! impl_intern_key { ($id:ident, $loc:ident) => { diff --git a/crates/hir-def/src/expr_store/lower.rs b/crates/hir-def/src/expr_store/lower.rs index 89eeaf00bc..4ba31c1e20 100644 --- a/crates/hir-def/src/expr_store/lower.rs +++ b/crates/hir-def/src/expr_store/lower.rs @@ -7,6 +7,7 @@ mod path; use std::mem; +use base_db::FxIndexSet; use cfg::CfgOptions; use either::Either; use hir_expand::{ @@ -66,8 +67,6 @@ use crate::{ pub use self::path::hir_segment_to_ast_segment; -type FxIndexSet = indexmap::IndexSet>; - pub(super) fn lower_body( db: &dyn DefDatabase, owner: DefWithBodyId, diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs index 07d1500fc0..81c8f56456 100644 --- a/crates/hir-def/src/item_tree.rs +++ b/crates/hir-def/src/item_tree.rs @@ -246,7 +246,7 @@ impl ItemTree { macro_calls, macro_rules, macro_defs, - vis, + vis: _, } = &mut **data; uses.shrink_to_fit(); @@ -266,36 +266,13 @@ impl ItemTree { macro_calls.shrink_to_fit(); macro_rules.shrink_to_fit(); macro_defs.shrink_to_fit(); - - vis.arena.shrink_to_fit(); } } } #[derive(Default, Debug, Eq, PartialEq)] struct ItemVisibilities { - arena: Arena, -} - -impl ItemVisibilities { - fn alloc(&mut self, vis: RawVisibility) -> RawVisibilityId { - match &vis { - RawVisibility::Public => RawVisibilityId::PUB, - RawVisibility::Module(path, explicitiy) if path.segments().is_empty() => { - match (path.kind, explicitiy) { - (PathKind::SELF, VisibilityExplicitness::Explicit) => { - RawVisibilityId::PRIV_EXPLICIT - } - (PathKind::SELF, VisibilityExplicitness::Implicit) => { - RawVisibilityId::PRIV_IMPLICIT - } - (PathKind::Crate, _) => RawVisibilityId::PUB_CRATE, - _ => RawVisibilityId(self.arena.alloc(vis).into_raw().into()), - } - } - _ => RawVisibilityId(self.arena.alloc(vis).into_raw().into()), - } - } + arena: Box<[RawVisibility]>, } #[derive(Default, Debug, Eq, PartialEq)] @@ -577,7 +554,7 @@ impl Index for ItemTree { VisibilityExplicitness::Explicit, ) }), - _ => &self.data().vis.arena[Idx::from_raw(index.0.into())], + _ => &self.data().vis.arena[index.0 as usize], } } } @@ -702,7 +679,7 @@ pub enum FieldsShape { } /// Visibility of an item, not yet resolved. -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum RawVisibility { /// `pub(in module)`, `pub(crate)` or `pub(super)`. Also private, which is /// equivalent to `pub(self)`. diff --git a/crates/hir-def/src/item_tree/lower.rs b/crates/hir-def/src/item_tree/lower.rs index d9588cb487..26d209c972 100644 --- a/crates/hir-def/src/item_tree/lower.rs +++ b/crates/hir-def/src/item_tree/lower.rs @@ -2,6 +2,7 @@ use std::{cell::OnceCell, collections::hash_map::Entry}; +use base_db::FxIndexSet; use hir_expand::{ HirFileId, mod_path::PathKind, @@ -37,6 +38,7 @@ pub(super) struct Ctx<'a> { source_ast_id_map: Arc, span_map: OnceCell, file: HirFileId, + visibilities: FxIndexSet, } impl<'a> Ctx<'a> { @@ -47,6 +49,7 @@ impl<'a> Ctx<'a> { source_ast_id_map: db.ast_id_map(file), file, span_map: OnceCell::new(), + visibilities: FxIndexSet::default(), } } @@ -57,6 +60,9 @@ impl<'a> Ctx<'a> { pub(super) fn lower_module_items(mut self, item_owner: &dyn HasModuleItem) -> ItemTree { self.tree.top_level = item_owner.items().flat_map(|item| self.lower_mod_item(&item)).collect(); + if let Some(data) = &mut self.tree.data { + data.vis.arena = self.visibilities.into_iter().collect(); + } self.tree } @@ -90,6 +96,9 @@ impl<'a> Ctx<'a> { } } + if let Some(data) = &mut self.tree.data { + data.vis.arena = self.visibilities.into_iter().collect(); + } self.tree } @@ -115,7 +124,9 @@ impl<'a> Ctx<'a> { } } } - + if let Some(data) = &mut self.tree.data { + data.vis.arena = self.visibilities.into_iter().collect(); + } self.tree } @@ -370,7 +381,22 @@ impl<'a> Ctx<'a> { let vis = visibility_from_ast(self.db, item.visibility(), &mut |range| { self.span_map().span_for_range(range).ctx }); - self.data().vis.alloc(vis) + match &vis { + RawVisibility::Public => RawVisibilityId::PUB, + RawVisibility::Module(path, explicitiy) if path.segments().is_empty() => { + match (path.kind, explicitiy) { + (PathKind::SELF, VisibilityExplicitness::Explicit) => { + RawVisibilityId::PRIV_EXPLICIT + } + (PathKind::SELF, VisibilityExplicitness::Implicit) => { + RawVisibilityId::PRIV_IMPLICIT + } + (PathKind::Crate, _) => RawVisibilityId::PUB_CRATE, + _ => RawVisibilityId(self.visibilities.insert_full(vis).0 as u32), + } + } + _ => RawVisibilityId(self.visibilities.insert_full(vis).0 as u32), + } } } diff --git a/crates/hir/src/symbols.rs b/crates/hir/src/symbols.rs index e87ab87407..a0815c3131 100644 --- a/crates/hir/src/symbols.rs +++ b/crates/hir/src/symbols.rs @@ -1,5 +1,6 @@ //! File symbol extraction. +use base_db::FxIndexSet; use either::Either; use hir_def::{ AdtId, AssocItemId, Complete, DefWithBodyId, ExternCrateId, HasModule, ImplId, Lookup, MacroId, @@ -21,8 +22,6 @@ use syntax::{AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, ToSmolStr, ast use crate::{HasCrate, Module, ModuleDef, Semantics}; -pub type FxIndexSet = indexmap::IndexSet>; - /// The actual data that is stored in the index. It should be as compact as /// possible. #[derive(Debug, Clone, PartialEq, Eq, Hash)] diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs index ab13960240..f48150b369 100644 --- a/crates/ide/src/runnables.rs +++ b/crates/ide/src/runnables.rs @@ -5,11 +5,11 @@ use ast::HasName; use cfg::{CfgAtom, CfgExpr}; use hir::{ AsAssocItem, AttrsWithOwner, HasAttrs, HasCrate, HasSource, ModPath, Name, PathKind, Semantics, - Symbol, db::HirDatabase, sym, symbols::FxIndexSet, + Symbol, db::HirDatabase, sym, }; use ide_assists::utils::{has_test_related_attribute, test_related_attribute_syn}; use ide_db::{ - FilePosition, FxHashMap, FxIndexMap, RootDatabase, SymbolKind, + FilePosition, FxHashMap, FxIndexMap, FxIndexSet, RootDatabase, SymbolKind, base_db::RootQueryDb, defs::Definition, documentation::docs_from_attrs, From c8cedae2f9f384d40946eff4d2ccaa7ff42ff409 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 12 Jun 2025 09:36:22 +0200 Subject: [PATCH 16/56] fix: Do not force descend into derives for goto IDE features Doing so can cause us to duplicate navigation targets for the same ranges which breaks convenience features of some editors where go to def can trigger find all references --- crates/hir/src/semantics.rs | 5 +++-- crates/ide/src/goto_declaration.rs | 2 +- crates/ide/src/goto_definition.rs | 2 +- crates/ide/src/goto_type_definition.rs | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 47607a51d3..1049895824 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -244,7 +244,7 @@ impl Semantics<'_, DB> { offset: TextSize, ) -> impl Iterator + 'slf { node.token_at_offset(offset) - .map(move |token| self.descend_into_macros_no_opaque(token)) + .map(move |token| self.descend_into_macros_no_opaque(token, true)) .map(|descendants| descendants.into_iter().filter_map(move |it| it.value.parent())) // re-order the tokens from token_at_offset by returning the ancestors with the smaller first nodes first // See algo::ancestors_at_offset, which uses the same approach @@ -1009,10 +1009,11 @@ impl<'db> SemanticsImpl<'db> { pub fn descend_into_macros_no_opaque( &self, token: SyntaxToken, + always_descend_into_derives: bool, ) -> SmallVec<[InFile; 1]> { let mut res = smallvec![]; let token = self.wrap_token_infile(token); - self.descend_into_macros_all(token.clone(), true, &mut |t, ctx| { + self.descend_into_macros_all(token.clone(), always_descend_into_derives, &mut |t, ctx| { if !ctx.is_opaque(self.db) { // Don't descend into opaque contexts res.push(t); diff --git a/crates/ide/src/goto_declaration.rs b/crates/ide/src/goto_declaration.rs index 38c032d382..267e8ff712 100644 --- a/crates/ide/src/goto_declaration.rs +++ b/crates/ide/src/goto_declaration.rs @@ -29,7 +29,7 @@ pub(crate) fn goto_declaration( .find(|it| matches!(it.kind(), IDENT | T![self] | T![super] | T![crate] | T![Self]))?; let range = original_token.text_range(); let info: Vec = sema - .descend_into_macros_no_opaque(original_token) + .descend_into_macros_no_opaque(original_token, false) .iter() .filter_map(|token| { let parent = token.value.parent()?; diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs index 7917aab8bf..574803fb9e 100644 --- a/crates/ide/src/goto_definition.rs +++ b/crates/ide/src/goto_definition.rs @@ -88,7 +88,7 @@ pub(crate) fn goto_definition( } let navs = sema - .descend_into_macros_no_opaque(original_token.clone()) + .descend_into_macros_no_opaque(original_token.clone(), false) .into_iter() .filter_map(|token| { let parent = token.value.parent()?; diff --git a/crates/ide/src/goto_type_definition.rs b/crates/ide/src/goto_type_definition.rs index a6c7ea29b0..9781e7116d 100644 --- a/crates/ide/src/goto_type_definition.rs +++ b/crates/ide/src/goto_type_definition.rs @@ -70,7 +70,7 @@ pub(crate) fn goto_type_definition( } let range = token.text_range(); - sema.descend_into_macros_no_opaque(token) + sema.descend_into_macros_no_opaque(token,false) .into_iter() .filter_map(|token| { sema From e9f8ecab45bf345e25f7a2f1a786ea7e25631b68 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 12 Jun 2025 09:46:01 +0200 Subject: [PATCH 17/56] Remove `ItemTreeId` --- crates/hir-def/src/attr.rs | 19 ++++++--- crates/hir-def/src/item_tree.rs | 53 ------------------------- crates/hir-def/src/nameres.rs | 34 +++++++++------- crates/hir-def/src/nameres/collector.rs | 32 +++++++++------ 4 files changed, 52 insertions(+), 86 deletions(-) diff --git a/crates/hir-def/src/attr.rs b/crates/hir-def/src/attr.rs index a7328809a8..cc9a2fdf4c 100644 --- a/crates/hir-def/src/attr.rs +++ b/crates/hir-def/src/attr.rs @@ -523,10 +523,15 @@ impl AttrsWithOwner { let mod_data = &def_map[module.local_id]; let raw_attrs = match mod_data.origin { - ModuleOrigin::File { definition, declaration_tree_id, .. } => { + ModuleOrigin::File { + definition, + declaration_tree_id, + file_item_tree_id, + .. + } => { let decl_attrs = declaration_tree_id .item_tree(db) - .raw_attrs(AttrOwner::ModItem(declaration_tree_id.value.into())) + .raw_attrs(AttrOwner::ModItem(file_item_tree_id.into())) .clone(); let tree = db.file_item_tree(definition.into()); let def_attrs = tree.raw_attrs(AttrOwner::TopLevel).clone(); @@ -536,10 +541,12 @@ impl AttrsWithOwner { let tree = db.file_item_tree(definition.into()); tree.raw_attrs(AttrOwner::TopLevel).clone() } - ModuleOrigin::Inline { definition_tree_id, .. } => definition_tree_id - .item_tree(db) - .raw_attrs(AttrOwner::ModItem(definition_tree_id.value.into())) - .clone(), + ModuleOrigin::Inline { definition_tree_id, file_item_tree_id, .. } => { + definition_tree_id + .item_tree(db) + .raw_attrs(AttrOwner::ModItem(file_item_tree_id.into())) + .clone() + } ModuleOrigin::BlockExpr { id, .. } => { let tree = db.block_item_tree(id); tree.raw_attrs(AttrOwner::TopLevel).clone() diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs index 81c8f56456..ec2b65c9c0 100644 --- a/crates/hir-def/src/item_tree.rs +++ b/crates/hir-def/src/item_tree.rs @@ -404,59 +404,6 @@ impl TreeId { } } -#[derive(Debug)] -pub struct ItemTreeId { - tree: TreeId, - pub value: FileItemTreeId, -} - -impl ItemTreeId { - pub fn new(tree: TreeId, idx: FileItemTreeId) -> Self { - Self { tree, value: idx } - } - - pub fn file_id(self) -> HirFileId { - self.tree.file - } - - pub fn tree_id(self) -> TreeId { - self.tree - } - - pub fn item_tree(self, db: &dyn DefDatabase) -> Arc { - self.tree.item_tree(db) - } - - pub fn resolved(self, db: &dyn DefDatabase, cb: impl FnOnce(&N) -> R) -> R - where - ItemTree: Index, Output = N>, - { - cb(&self.tree.item_tree(db)[self.value]) - } -} - -impl Copy for ItemTreeId {} -impl Clone for ItemTreeId { - fn clone(&self) -> Self { - *self - } -} - -impl PartialEq for ItemTreeId { - fn eq(&self, other: &Self) -> bool { - self.tree == other.tree && self.value == other.value - } -} - -impl Eq for ItemTreeId {} - -impl Hash for ItemTreeId { - fn hash(&self, state: &mut H) { - self.tree.hash(state); - self.value.hash(state); - } -} - macro_rules! mod_items { ( $( $typ:ident in $fld:ident -> $ast:ty ),+ $(,)? ) => { #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] diff --git a/crates/hir-def/src/nameres.rs b/crates/hir-def/src/nameres.rs index c908e45754..e62fd3dab7 100644 --- a/crates/hir-def/src/nameres.rs +++ b/crates/hir-def/src/nameres.rs @@ -80,7 +80,7 @@ use crate::{ LocalModuleId, Lookup, MacroExpander, MacroId, ModuleId, ProcMacroId, UseId, db::DefDatabase, item_scope::{BuiltinShadowMode, ItemScope}, - item_tree::{ItemTreeId, Mod, TreeId}, + item_tree::{FileItemTreeId, Mod, TreeId}, nameres::{diagnostics::DefDiagnostic, path_resolution::ResolveMode}, per_ns::PerNs, visibility::{Visibility, VisibilityExplicitness}, @@ -289,11 +289,13 @@ pub enum ModuleOrigin { File { is_mod_rs: bool, declaration: FileAstId, - declaration_tree_id: ItemTreeId, + declaration_tree_id: TreeId, + file_item_tree_id: FileItemTreeId, definition: EditionedFileId, }, Inline { - definition_tree_id: ItemTreeId, + definition_tree_id: TreeId, + file_item_tree_id: FileItemTreeId, definition: FileAstId, }, /// Pseudo-module introduced by a block scope (contains only inner items). @@ -309,7 +311,7 @@ impl ModuleOrigin { &ModuleOrigin::File { declaration, declaration_tree_id, .. } => { Some(AstId::new(declaration_tree_id.file_id(), declaration)) } - &ModuleOrigin::Inline { definition, definition_tree_id } => { + &ModuleOrigin::Inline { definition, definition_tree_id, file_item_tree_id: _ } => { Some(AstId::new(definition_tree_id.file_id(), definition)) } ModuleOrigin::CrateRoot { .. } | ModuleOrigin::BlockExpr { .. } => None, @@ -341,12 +343,14 @@ impl ModuleOrigin { let sf = db.parse(editioned_file_id).tree(); InFile::new(editioned_file_id.into(), ModuleSource::SourceFile(sf)) } - &ModuleOrigin::Inline { definition, definition_tree_id } => InFile::new( - definition_tree_id.file_id(), - ModuleSource::Module( - AstId::new(definition_tree_id.file_id(), definition).to_node(db), - ), - ), + &ModuleOrigin::Inline { definition, definition_tree_id, file_item_tree_id: _ } => { + InFile::new( + definition_tree_id.file_id(), + ModuleSource::Module( + AstId::new(definition_tree_id.file_id(), definition).to_node(db), + ), + ) + } ModuleOrigin::BlockExpr { block, .. } => { InFile::new(block.file_id, ModuleSource::BlockExpr(block.to_node(db))) } @@ -773,10 +777,12 @@ impl ModuleData { ErasedAstId::new(definition.into(), ROOT_ERASED_FILE_AST_ID).to_range(db), ) } - &ModuleOrigin::Inline { definition, definition_tree_id } => InFile::new( - definition_tree_id.file_id(), - AstId::new(definition_tree_id.file_id(), definition).to_range(db), - ), + &ModuleOrigin::Inline { definition, definition_tree_id, file_item_tree_id: _ } => { + InFile::new( + definition_tree_id.file_id(), + AstId::new(definition_tree_id.file_id(), definition).to_range(db), + ) + } ModuleOrigin::BlockExpr { block, .. } => InFile::new(block.file_id, block.to_range(db)), } } diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index 34a129a88e..e2231857fd 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -35,8 +35,8 @@ use crate::{ db::DefDatabase, item_scope::{GlobId, ImportId, ImportOrExternCrate, PerNsGlobImports}, item_tree::{ - self, FieldsShape, FileItemTreeId, ImportAlias, ImportKind, ItemTree, ItemTreeId, - ItemTreeNode, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, TreeId, UseTreeKind, + self, FieldsShape, FileItemTreeId, ImportAlias, ImportKind, ItemTree, ItemTreeNode, Macro2, + MacroCall, MacroRules, Mod, ModItem, ModKind, TreeId, UseTreeKind, }, macro_call_as_call_id, nameres::{ @@ -140,7 +140,8 @@ struct ImportSource { id: UseId, is_prelude: bool, kind: ImportKind, - item_tree_id: ItemTreeId, + tree: TreeId, + item: FileItemTreeId, } #[derive(Debug, Eq, PartialEq)] @@ -154,19 +155,20 @@ struct Import { impl Import { fn from_use( tree: &ItemTree, - item_tree_id: ItemTreeId, + tree_id: TreeId, + item: FileItemTreeId, id: UseId, is_prelude: bool, mut cb: impl FnMut(Self), ) { - let it = &tree[item_tree_id.value]; + let it = &tree[item]; let visibility = &tree[it.visibility]; it.use_tree.expand(|idx, path, kind, alias| { cb(Self { path, alias, visibility: visibility.clone(), - source: ImportSource { use_tree: idx, id, is_prelude, kind, item_tree_id }, + source: ImportSource { use_tree: idx, id, is_prelude, kind, tree: tree_id, item }, }); }); } @@ -860,7 +862,8 @@ impl DefCollector<'_> { kind: kind @ (ImportKind::Plain | ImportKind::TypeOnly), id, use_tree, - item_tree_id, + tree, + item, .. } => { let name = match &import.alias { @@ -893,8 +896,8 @@ impl DefCollector<'_> { 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 item_tree = tree.item_tree(self.db); + let use_kind = item_tree[item].use_tree.kind(); let UseTreeKind::Single { path, .. } = use_kind else { return false; }; @@ -1643,7 +1646,7 @@ impl DefCollector<'_> { Import { ref path, source: - ImportSource { use_tree, id, is_prelude: _, kind: _, item_tree_id: _ }, + ImportSource { use_tree, id, is_prelude: _, kind: _, tree: _, item: _ }, .. }, .. @@ -1771,7 +1774,8 @@ impl ModCollector<'_, '_> { let is_prelude = attrs.by_key(sym::prelude_import).exists(); Import::from_use( self.item_tree, - ItemTreeId::new(self.tree_id, item_tree_id), + self.tree_id, + item_tree_id, id, is_prelude, |import| { @@ -2207,13 +2211,15 @@ impl ModCollector<'_, '_> { let origin = match definition { None => ModuleOrigin::Inline { definition: declaration, - definition_tree_id: ItemTreeId::new(self.tree_id, mod_tree_id), + definition_tree_id: self.tree_id, + file_item_tree_id: mod_tree_id, }, Some((definition, is_mod_rs)) => ModuleOrigin::File { declaration, definition, is_mod_rs, - declaration_tree_id: ItemTreeId::new(self.tree_id, mod_tree_id), + declaration_tree_id: self.tree_id, + file_item_tree_id: mod_tree_id, }, }; From f3434f537f3f4409b44c99e7c688f71dee42554d Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 12 Jun 2025 10:17:45 +0200 Subject: [PATCH 18/56] Remove `FileItemTreeId` --- crates/hir-def/src/attr.rs | 19 ++-- crates/hir-def/src/item_tree.rs | 115 +++++++----------------- crates/hir-def/src/item_tree/lower.rs | 102 +++++++++++---------- crates/hir-def/src/nameres.rs | 30 +++---- crates/hir-def/src/nameres/collector.rs | 31 +++---- 5 files changed, 116 insertions(+), 181 deletions(-) diff --git a/crates/hir-def/src/attr.rs b/crates/hir-def/src/attr.rs index cc9a2fdf4c..e1bf6fde8a 100644 --- a/crates/hir-def/src/attr.rs +++ b/crates/hir-def/src/attr.rs @@ -523,15 +523,10 @@ impl AttrsWithOwner { let mod_data = &def_map[module.local_id]; let raw_attrs = match mod_data.origin { - ModuleOrigin::File { - definition, - declaration_tree_id, - file_item_tree_id, - .. - } => { + ModuleOrigin::File { definition, declaration_tree_id, declaration, .. } => { let decl_attrs = declaration_tree_id .item_tree(db) - .raw_attrs(AttrOwner::ModItem(file_item_tree_id.into())) + .raw_attrs(AttrOwner::ModItem(declaration.into())) .clone(); let tree = db.file_item_tree(definition.into()); let def_attrs = tree.raw_attrs(AttrOwner::TopLevel).clone(); @@ -541,12 +536,10 @@ impl AttrsWithOwner { let tree = db.file_item_tree(definition.into()); tree.raw_attrs(AttrOwner::TopLevel).clone() } - ModuleOrigin::Inline { definition_tree_id, file_item_tree_id, .. } => { - definition_tree_id - .item_tree(db) - .raw_attrs(AttrOwner::ModItem(file_item_tree_id.into())) - .clone() - } + ModuleOrigin::Inline { definition_tree_id, definition } => definition_tree_id + .item_tree(db) + .raw_attrs(AttrOwner::ModItem(definition.into())) + .clone(), ModuleOrigin::BlockExpr { id, .. } => { let tree = db.block_item_tree(id); tree.raw_attrs(AttrOwner::TopLevel).clone() diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs index ec2b65c9c0..578f5fdee2 100644 --- a/crates/hir-def/src/item_tree.rs +++ b/crates/hir-def/src/item_tree.rs @@ -37,8 +37,8 @@ mod tests; use std::{ fmt::{self, Debug}, - hash::{Hash, Hasher}, - ops::{Index, Range}, + hash::Hash, + ops::Index, sync::OnceLock, }; @@ -51,7 +51,7 @@ use hir_expand::{ name::Name, }; use intern::Interned; -use la_arena::{Arena, Idx, RawIdx}; +use la_arena::{Arena, Idx}; use rustc_hash::FxHashMap; use smallvec::SmallVec; use span::{AstIdNode, Edition, FileAstId, SyntaxContext}; @@ -277,23 +277,23 @@ struct ItemVisibilities { #[derive(Default, Debug, Eq, PartialEq)] struct ItemTreeData { - uses: Arena, - extern_crates: Arena, - extern_blocks: Arena, - functions: Arena, - structs: Arena, - unions: Arena, - enums: Arena, - consts: Arena, - statics: Arena, - traits: Arena, - trait_aliases: Arena, - impls: Arena, - type_aliases: Arena, - mods: Arena, - macro_calls: Arena, - macro_rules: Arena, - macro_defs: Arena, + uses: FxHashMap, Use>, + extern_crates: FxHashMap, ExternCrate>, + extern_blocks: FxHashMap, ExternBlock>, + functions: FxHashMap, Function>, + structs: FxHashMap, Struct>, + unions: FxHashMap, Union>, + enums: FxHashMap, Enum>, + consts: FxHashMap, Const>, + statics: FxHashMap, Static>, + traits: FxHashMap, Trait>, + trait_aliases: FxHashMap, TraitAlias>, + impls: FxHashMap, Impl>, + type_aliases: FxHashMap, TypeAlias>, + mods: FxHashMap, Mod>, + macro_calls: FxHashMap, MacroCall>, + macro_rules: FxHashMap, MacroRules>, + macro_defs: FxHashMap, Macro2>, vis: ItemVisibilities, } @@ -329,51 +329,11 @@ pub trait ItemTreeNode: Clone { fn ast_id(&self) -> FileAstId; /// Looks up an instance of `Self` in an item tree. - fn lookup(tree: &ItemTree, index: Idx) -> &Self; + fn lookup(tree: &ItemTree, index: FileAstId) -> &Self; } -pub struct FileItemTreeId(Idx); - -impl FileItemTreeId { - pub fn range_iter(range: Range) -> impl Iterator + Clone { - (range.start.index().into_raw().into_u32()..range.end.index().into_raw().into_u32()) - .map(RawIdx::from_u32) - .map(Idx::from_raw) - .map(Self) - } -} - -impl FileItemTreeId { - pub fn index(&self) -> Idx { - self.0 - } -} - -impl Clone for FileItemTreeId { - fn clone(&self) -> Self { - *self - } -} -impl Copy for FileItemTreeId {} - -impl PartialEq for FileItemTreeId { - fn eq(&self, other: &FileItemTreeId) -> bool { - self.0 == other.0 - } -} -impl Eq for FileItemTreeId {} - -impl Hash for FileItemTreeId { - fn hash(&self, state: &mut H) { - self.0.hash(state) - } -} - -impl fmt::Debug for FileItemTreeId { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} +#[allow(type_alias_bounds)] +pub type ItemTreeAstId = FileAstId; /// Identifies a particular [`ItemTree`]. #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] @@ -409,21 +369,21 @@ macro_rules! mod_items { #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum ModItem { $( - $typ(FileItemTreeId<$typ>), + $typ(FileAstId<$ast>), )+ } impl ModItem { - pub fn ast_id(&self, tree: &ItemTree) -> FileAstId { + pub fn ast_id(self) -> FileAstId { match self { - $(ModItem::$typ(it) => tree[it.index()].ast_id().upcast()),+ + $(ModItem::$typ(it) => it.upcast()),+ } } } $( - impl From> for ModItem { - fn from(id: FileItemTreeId<$typ>) -> ModItem { + impl From> for ModItem { + fn from(id: FileAstId<$ast>) -> ModItem { ModItem::$typ(id) } } @@ -433,20 +393,20 @@ macro_rules! mod_items { impl ItemTreeNode for $typ { type Source = $ast; - fn ast_id(&self) -> FileAstId { + fn ast_id(&self) -> FileAstId<$ast> { self.ast_id } - fn lookup(tree: &ItemTree, index: Idx) -> &Self { - &tree.data().$fld[index] + fn lookup(tree: &ItemTree, index: FileAstId<$ast>) -> &Self { + &tree.data().$fld[&index] } } - impl Index> for ItemTree { + impl Index> for ItemTree { type Output = $typ; - fn index(&self, index: Idx<$typ>) -> &Self::Output { - &self.data().$fld[index] + fn index(&self, index: FileAstId<$ast>) -> &Self::Output { + &self.data().$fld[&index] } } )+ @@ -506,13 +466,6 @@ impl Index for ItemTree { } } -impl Index> for ItemTree { - type Output = N; - fn index(&self, id: FileItemTreeId) -> &N { - N::lookup(self, id.index()) - } -} - #[derive(Debug, Clone, Eq, PartialEq)] pub struct Use { pub visibility: RawVisibilityId, diff --git a/crates/hir-def/src/item_tree/lower.rs b/crates/hir-def/src/item_tree/lower.rs index 26d209c972..17b115b6ec 100644 --- a/crates/hir-def/src/item_tree/lower.rs +++ b/crates/hir-def/src/item_tree/lower.rs @@ -20,18 +20,14 @@ use triomphe::Arc; use crate::{ db::DefDatabase, item_tree::{ - 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, + AttrOwner, Const, Enum, ExternBlock, ExternCrate, FieldsShape, Function, Impl, ImportAlias, + Interned, ItemTree, ItemTreeAstId, ItemTreeData, Macro2, MacroCall, MacroRules, Mod, + ModItem, ModKind, ModPath, RawAttrs, RawVisibility, RawVisibilityId, Static, Struct, StructKind, Trait, TraitAlias, TypeAlias, Union, Use, UseTree, UseTreeKind, VisibilityExplicitness, }, }; -fn id(index: Idx) -> FileItemTreeId { - FileItemTreeId(index) -} - pub(super) struct Ctx<'a> { db: &'a dyn DefDatabase, tree: ItemTree, @@ -173,36 +169,36 @@ impl<'a> Ctx<'a> { } } - fn lower_struct(&mut self, strukt: &ast::Struct) -> Option> { + 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 shape = adt_shape(strukt.kind()); let res = Struct { name, visibility, shape, ast_id }; - let id = id(self.data().structs.alloc(res)); + self.data().structs.insert(ast_id, res); - Some(id) + Some(ast_id) } - fn lower_union(&mut self, union: &ast::Union) -> Option> { + 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 res = Union { name, visibility, ast_id }; - let id = id(self.data().unions.alloc(res)); - Some(id) + self.data().unions.insert(ast_id, res); + Some(ast_id) } - fn lower_enum(&mut self, enum_: &ast::Enum) -> Option> { + fn lower_enum(&mut self, enum_: &ast::Enum) -> Option> { let visibility = self.lower_visibility(enum_); let name = enum_.name()?.as_name(); let ast_id = self.source_ast_id_map.ast_id(enum_); let res = Enum { name, visibility, ast_id }; - let id = id(self.data().enums.alloc(res)); - Some(id) + self.data().enums.insert(ast_id, res); + Some(ast_id) } - fn lower_function(&mut self, func: &ast::Fn) -> Option> { + fn lower_function(&mut self, func: &ast::Fn) -> Option> { let visibility = self.lower_visibility(func); let name = func.name()?.as_name(); @@ -210,39 +206,41 @@ impl<'a> Ctx<'a> { let res = Function { name, visibility, ast_id }; - let id = id(self.data().functions.alloc(res)); - Some(id) + self.data().functions.insert(ast_id, res); + Some(ast_id) } fn lower_type_alias( &mut self, type_alias: &ast::TypeAlias, - ) -> Option> { + ) -> Option> { let name = type_alias.name()?.as_name(); let visibility = self.lower_visibility(type_alias); let ast_id = self.source_ast_id_map.ast_id(type_alias); let res = TypeAlias { name, visibility, ast_id }; - let id = id(self.data().type_aliases.alloc(res)); - Some(id) + self.data().type_aliases.insert(ast_id, res); + Some(ast_id) } - fn lower_static(&mut self, static_: &ast::Static) -> Option> { + fn lower_static(&mut self, static_: &ast::Static) -> Option> { let name = static_.name()?.as_name(); let visibility = self.lower_visibility(static_); let ast_id = self.source_ast_id_map.ast_id(static_); let res = Static { name, visibility, ast_id }; - Some(id(self.data().statics.alloc(res))) + self.data().statics.insert(ast_id, res); + Some(ast_id) } - fn lower_const(&mut self, konst: &ast::Const) -> FileItemTreeId { + fn lower_const(&mut self, konst: &ast::Const) -> ItemTreeAstId { let name = konst.name().map(|it| it.as_name()); let visibility = self.lower_visibility(konst); let ast_id = self.source_ast_id_map.ast_id(konst); let res = Const { name, visibility, ast_id }; - id(self.data().consts.alloc(res)) + self.data().consts.insert(ast_id, res); + ast_id } - fn lower_module(&mut self, module: &ast::Module) -> Option> { + fn lower_module(&mut self, module: &ast::Module) -> Option> { let name = module.name()?.as_name(); let visibility = self.lower_visibility(module); let kind = if module.semicolon_token().is_some() { @@ -260,41 +258,43 @@ impl<'a> Ctx<'a> { }; let ast_id = self.source_ast_id_map.ast_id(module); let res = Mod { name, visibility, kind, ast_id }; - Some(id(self.data().mods.alloc(res))) + self.data().mods.insert(ast_id, res); + Some(ast_id) } - fn lower_trait(&mut self, trait_def: &ast::Trait) -> Option> { + fn lower_trait(&mut self, trait_def: &ast::Trait) -> Option> { let name = trait_def.name()?.as_name(); let visibility = self.lower_visibility(trait_def); let ast_id = self.source_ast_id_map.ast_id(trait_def); let def = Trait { name, visibility, ast_id }; - let id = id(self.data().traits.alloc(def)); - Some(id) + self.data().traits.insert(ast_id, def); + Some(ast_id) } fn lower_trait_alias( &mut self, trait_alias_def: &ast::TraitAlias, - ) -> Option> { + ) -> Option> { let name = trait_alias_def.name()?.as_name(); let visibility = self.lower_visibility(trait_alias_def); let ast_id = self.source_ast_id_map.ast_id(trait_alias_def); let alias = TraitAlias { name, visibility, ast_id }; - let id = id(self.data().trait_aliases.alloc(alias)); - Some(id) + self.data().trait_aliases.insert(ast_id, alias); + Some(ast_id) } - fn lower_impl(&mut self, impl_def: &ast::Impl) -> FileItemTreeId { + fn lower_impl(&mut self, impl_def: &ast::Impl) -> ItemTreeAstId { let ast_id = self.source_ast_id_map.ast_id(impl_def); // 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 { ast_id }; - id(self.data().impls.alloc(res)) + self.data().impls.insert(ast_id, res); + ast_id } - fn lower_use(&mut self, use_item: &ast::Use) -> Option> { + fn lower_use(&mut self, use_item: &ast::Use) -> Option> { let visibility = self.lower_visibility(use_item); let ast_id = self.source_ast_id_map.ast_id(use_item); let (use_tree, _) = lower_use_tree(self.db, use_item.use_tree()?, &mut |range| { @@ -302,13 +302,14 @@ impl<'a> Ctx<'a> { })?; let res = Use { visibility, ast_id, use_tree }; - Some(id(self.data().uses.alloc(res))) + self.data().uses.insert(ast_id, res); + Some(ast_id) } fn lower_extern_crate( &mut self, extern_crate: &ast::ExternCrate, - ) -> Option> { + ) -> Option> { let name = extern_crate.name_ref()?.as_name(); let alias = extern_crate.rename().map(|a| { a.name().map(|it| it.as_name()).map_or(ImportAlias::Underscore, ImportAlias::Alias) @@ -317,10 +318,11 @@ impl<'a> Ctx<'a> { let ast_id = self.source_ast_id_map.ast_id(extern_crate); let res = ExternCrate { name, alias, visibility, ast_id }; - Some(id(self.data().extern_crates.alloc(res))) + self.data().extern_crates.insert(ast_id, res); + Some(ast_id) } - fn lower_macro_call(&mut self, m: &ast::MacroCall) -> Option> { + fn lower_macro_call(&mut self, m: &ast::MacroCall) -> Option> { let span_map = self.span_map(); let path = m.path()?; let range = path.syntax().text_range(); @@ -330,28 +332,31 @@ impl<'a> Ctx<'a> { let ast_id = self.source_ast_id_map.ast_id(m); let expand_to = hir_expand::ExpandTo::from_call_site(m); let res = MacroCall { path, ast_id, expand_to, ctxt: span_map.span_for_range(range).ctx }; - Some(id(self.data().macro_calls.alloc(res))) + self.data().macro_calls.insert(ast_id, res); + Some(ast_id) } - fn lower_macro_rules(&mut self, m: &ast::MacroRules) -> Option> { + fn lower_macro_rules(&mut self, m: &ast::MacroRules) -> Option> { let name = m.name()?; let ast_id = self.source_ast_id_map.ast_id(m); let res = MacroRules { name: name.as_name(), ast_id }; - Some(id(self.data().macro_rules.alloc(res))) + self.data().macro_rules.insert(ast_id, res); + Some(ast_id) } - fn lower_macro_def(&mut self, m: &ast::MacroDef) -> Option> { + fn lower_macro_def(&mut self, m: &ast::MacroDef) -> Option> { let name = m.name()?; let ast_id = self.source_ast_id_map.ast_id(m); let visibility = self.lower_visibility(m); let res = Macro2 { name: name.as_name(), ast_id, visibility }; - Some(id(self.data().macro_defs.alloc(res))) + self.data().macro_defs.insert(ast_id, res); + Some(ast_id) } - fn lower_extern_block(&mut self, block: &ast::ExternBlock) -> FileItemTreeId { + fn lower_extern_block(&mut self, block: &ast::ExternBlock) -> ItemTreeAstId { let ast_id = self.source_ast_id_map.ast_id(block); let children: Box<[_]> = block.extern_item_list().map_or(Box::new([]), |list| { list.extern_items() @@ -374,7 +379,8 @@ impl<'a> Ctx<'a> { }); let res = ExternBlock { ast_id, children }; - id(self.data().extern_blocks.alloc(res)) + self.data().extern_blocks.insert(ast_id, res); + ast_id } fn lower_visibility(&mut self, item: &dyn ast::HasVisibility) -> RawVisibilityId { diff --git a/crates/hir-def/src/nameres.rs b/crates/hir-def/src/nameres.rs index e62fd3dab7..610bb6b00b 100644 --- a/crates/hir-def/src/nameres.rs +++ b/crates/hir-def/src/nameres.rs @@ -80,7 +80,7 @@ use crate::{ LocalModuleId, Lookup, MacroExpander, MacroId, ModuleId, ProcMacroId, UseId, db::DefDatabase, item_scope::{BuiltinShadowMode, ItemScope}, - item_tree::{FileItemTreeId, Mod, TreeId}, + item_tree::TreeId, nameres::{diagnostics::DefDiagnostic, path_resolution::ResolveMode}, per_ns::PerNs, visibility::{Visibility, VisibilityExplicitness}, @@ -290,12 +290,10 @@ pub enum ModuleOrigin { is_mod_rs: bool, declaration: FileAstId, declaration_tree_id: TreeId, - file_item_tree_id: FileItemTreeId, definition: EditionedFileId, }, Inline { definition_tree_id: TreeId, - file_item_tree_id: FileItemTreeId, definition: FileAstId, }, /// Pseudo-module introduced by a block scope (contains only inner items). @@ -311,7 +309,7 @@ impl ModuleOrigin { &ModuleOrigin::File { declaration, declaration_tree_id, .. } => { Some(AstId::new(declaration_tree_id.file_id(), declaration)) } - &ModuleOrigin::Inline { definition, definition_tree_id, file_item_tree_id: _ } => { + &ModuleOrigin::Inline { definition, definition_tree_id } => { Some(AstId::new(definition_tree_id.file_id(), definition)) } ModuleOrigin::CrateRoot { .. } | ModuleOrigin::BlockExpr { .. } => None, @@ -343,14 +341,12 @@ impl ModuleOrigin { let sf = db.parse(editioned_file_id).tree(); InFile::new(editioned_file_id.into(), ModuleSource::SourceFile(sf)) } - &ModuleOrigin::Inline { definition, definition_tree_id, file_item_tree_id: _ } => { - InFile::new( - definition_tree_id.file_id(), - ModuleSource::Module( - AstId::new(definition_tree_id.file_id(), definition).to_node(db), - ), - ) - } + &ModuleOrigin::Inline { definition, definition_tree_id } => InFile::new( + definition_tree_id.file_id(), + ModuleSource::Module( + AstId::new(definition_tree_id.file_id(), definition).to_node(db), + ), + ), ModuleOrigin::BlockExpr { block, .. } => { InFile::new(block.file_id, ModuleSource::BlockExpr(block.to_node(db))) } @@ -777,12 +773,10 @@ impl ModuleData { ErasedAstId::new(definition.into(), ROOT_ERASED_FILE_AST_ID).to_range(db), ) } - &ModuleOrigin::Inline { definition, definition_tree_id, file_item_tree_id: _ } => { - InFile::new( - definition_tree_id.file_id(), - AstId::new(definition_tree_id.file_id(), definition).to_range(db), - ) - } + &ModuleOrigin::Inline { definition, definition_tree_id } => InFile::new( + definition_tree_id.file_id(), + AstId::new(definition_tree_id.file_id(), definition).to_range(db), + ), ModuleOrigin::BlockExpr { block, .. } => InFile::new(block.file_id, block.to_range(db)), } } diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index e2231857fd..a8ee92d813 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -35,7 +35,7 @@ use crate::{ db::DefDatabase, item_scope::{GlobId, ImportId, ImportOrExternCrate, PerNsGlobImports}, item_tree::{ - self, FieldsShape, FileItemTreeId, ImportAlias, ImportKind, ItemTree, ItemTreeNode, Macro2, + self, FieldsShape, ImportAlias, ImportKind, ItemTree, ItemTreeAstId, ItemTreeNode, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, TreeId, UseTreeKind, }, macro_call_as_call_id, @@ -141,7 +141,7 @@ struct ImportSource { is_prelude: bool, kind: ImportKind, tree: TreeId, - item: FileItemTreeId, + item: FileAstId, } #[derive(Debug, Eq, PartialEq)] @@ -156,7 +156,7 @@ impl Import { fn from_use( tree: &ItemTree, tree_id: TreeId, - item: FileItemTreeId, + item: FileAstId, id: UseId, is_prelude: bool, mut cb: impl FnMut(Self), @@ -2084,7 +2084,7 @@ impl ModCollector<'_, '_> { ); } - fn collect_module(&mut self, module_id: FileItemTreeId, attrs: &Attrs) { + fn collect_module(&mut self, module_id: ItemTreeAstId, attrs: &Attrs) { let path_attr = attrs.by_key(sym::path).string_value_unescape(); let is_macro_use = attrs.by_key(sym::macro_use).exists(); let module = &self.item_tree[module_id]; @@ -2096,7 +2096,6 @@ impl ModCollector<'_, '_> { module.ast_id, None, &self.item_tree[module.visibility], - module_id, ); let Some(mod_dir) = @@ -2151,7 +2150,6 @@ impl ModCollector<'_, '_> { ast_id.value, Some((file_id, is_mod_rs)), &self.item_tree[module.visibility], - module_id, ); ModCollector { def_collector: self.def_collector, @@ -2179,7 +2177,6 @@ impl ModCollector<'_, '_> { ast_id.value, None, &self.item_tree[module.visibility], - module_id, ); self.def_collector.def_map.diagnostics.push( DefDiagnostic::unresolved_module(self.module_id, ast_id, candidates), @@ -2196,7 +2193,6 @@ impl ModCollector<'_, '_> { declaration: FileAstId, definition: Option<(EditionedFileId, bool)>, visibility: &crate::visibility::RawVisibility, - mod_tree_id: FileItemTreeId, ) -> LocalModuleId { let def_map = &mut self.def_collector.def_map; let vis = def_map @@ -2209,17 +2205,14 @@ impl ModCollector<'_, '_> { ) .unwrap_or(Visibility::Public); let origin = match definition { - None => ModuleOrigin::Inline { - definition: declaration, - definition_tree_id: self.tree_id, - file_item_tree_id: mod_tree_id, - }, + None => { + ModuleOrigin::Inline { definition: declaration, definition_tree_id: self.tree_id } + } Some((definition, is_mod_rs)) => ModuleOrigin::File { declaration, definition, is_mod_rs, declaration_tree_id: self.tree_id, - file_item_tree_id: mod_tree_id, }, }; @@ -2294,11 +2287,7 @@ impl ModCollector<'_, '_> { attr.path.display(self.def_collector.db, Edition::LATEST) ); - let ast_id = AstIdWithPath::new( - self.file_id(), - mod_item.ast_id(self.item_tree), - attr.path.clone(), - ); + let ast_id = AstIdWithPath::new(self.file_id(), mod_item.ast_id(), attr.path.clone()); self.def_collector.unresolved_macros.push(MacroDirective { module_id: self.module_id, depth: self.macro_depth + 1, @@ -2317,7 +2306,7 @@ impl ModCollector<'_, '_> { Ok(()) } - fn collect_macro_rules(&mut self, id: FileItemTreeId, module: ModuleId) { + fn collect_macro_rules(&mut self, id: ItemTreeAstId, module: ModuleId) { let krate = self.def_collector.def_map.krate; let mac = &self.item_tree[id]; let attrs = self.item_tree.attrs(self.def_collector.db, krate, ModItem::from(id).into()); @@ -2402,7 +2391,7 @@ impl ModCollector<'_, '_> { ); } - fn collect_macro_def(&mut self, id: FileItemTreeId, module: ModuleId) { + fn collect_macro_def(&mut self, id: ItemTreeAstId, module: ModuleId) { let krate = self.def_collector.def_map.krate; let mac = &self.item_tree[id]; let ast_id = InFile::new(self.file_id(), mac.ast_id.upcast()); From 80996dca35454956a5de5a9ae36c461772343cf8 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 12 Jun 2025 10:25:21 +0200 Subject: [PATCH 19/56] `AttrOwner` needs no `ModItem` --- crates/hir-def/src/attr.rs | 4 +-- crates/hir-def/src/db.rs | 4 +-- crates/hir-def/src/item_tree.rs | 32 +++++++++--------- crates/hir-def/src/nameres/collector.rs | 43 +++++++++---------------- 4 files changed, 36 insertions(+), 47 deletions(-) diff --git a/crates/hir-def/src/attr.rs b/crates/hir-def/src/attr.rs index e1bf6fde8a..08986d68e5 100644 --- a/crates/hir-def/src/attr.rs +++ b/crates/hir-def/src/attr.rs @@ -526,7 +526,7 @@ impl AttrsWithOwner { ModuleOrigin::File { definition, declaration_tree_id, declaration, .. } => { let decl_attrs = declaration_tree_id .item_tree(db) - .raw_attrs(AttrOwner::ModItem(declaration.into())) + .raw_attrs(AttrOwner::Item(declaration.erase())) .clone(); let tree = db.file_item_tree(definition.into()); let def_attrs = tree.raw_attrs(AttrOwner::TopLevel).clone(); @@ -538,7 +538,7 @@ impl AttrsWithOwner { } ModuleOrigin::Inline { definition_tree_id, definition } => definition_tree_id .item_tree(db) - .raw_attrs(AttrOwner::ModItem(definition.into())) + .raw_attrs(AttrOwner::Item(definition.erase())) .clone(), ModuleOrigin::BlockExpr { id, .. } => { let tree = db.block_item_tree(id); diff --git a/crates/hir-def/src/db.rs b/crates/hir-def/src/db.rs index 362c0daa9b..95e33dde58 100644 --- a/crates/hir-def/src/db.rs +++ b/crates/hir-def/src/db.rs @@ -24,7 +24,7 @@ use crate::{ }, hir::generics::GenericParams, import_map::ImportMap, - item_tree::{AttrOwner, ItemTree}, + item_tree::ItemTree, lang_item::{self, LangItem}, nameres::{ assoc::{ImplItems, TraitItems}, @@ -376,7 +376,7 @@ fn include_macro_invoc( fn crate_supports_no_std(db: &dyn DefDatabase, crate_id: Crate) -> bool { let file = crate_id.data(db).root_file_id(db); let item_tree = db.file_item_tree(file.into()); - let attrs = item_tree.raw_attrs(AttrOwner::TopLevel); + let attrs = item_tree.raw_attrs(crate::item_tree::AttrOwner::TopLevel); for attr in &**attrs { match attr.path().as_ident() { Some(ident) if *ident == sym::no_std => return true, diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs index 578f5fdee2..4b3890ae96 100644 --- a/crates/hir-def/src/item_tree.rs +++ b/crates/hir-def/src/item_tree.rs @@ -51,10 +51,10 @@ use hir_expand::{ name::Name, }; use intern::Interned; -use la_arena::{Arena, Idx}; +use la_arena::Idx; use rustc_hash::FxHashMap; use smallvec::SmallVec; -use span::{AstIdNode, Edition, FileAstId, SyntaxContext}; +use span::{AstIdNode, Edition, ErasedFileAstId, FileAstId, SyntaxContext}; use stdx::never; use syntax::{SyntaxKind, ast, match_ast}; use triomphe::Arc; @@ -90,6 +90,7 @@ impl fmt::Debug for RawVisibilityId { #[derive(Debug, Default, Eq, PartialEq)] pub struct ItemTree { top_level: SmallVec<[ModItem; 1]>, + // Consider splitting this into top level RawAttrs and the map? attrs: FxHashMap, data: Option>, @@ -174,7 +175,7 @@ impl ItemTree { /// Returns an iterator over all items located at the top level of the `HirFileId` this /// `ItemTree` was created from. - pub fn top_level_items(&self) -> &[ModItem] { + pub(crate) fn top_level_items(&self) -> &[ModItem] { &self.top_level } @@ -310,7 +311,7 @@ pub struct ItemTreeDataStats { #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] pub enum AttrOwner { /// Attributes on an item. - ModItem(ModItem), + Item(ErasedFileAstId), /// Inner attributes of the source file. TopLevel, } @@ -318,7 +319,7 @@ pub enum AttrOwner { impl From for AttrOwner { #[inline] fn from(value: ModItem) -> Self { - AttrOwner::ModItem(value) + AttrOwner::Item(value.ast_id().erase()) } } @@ -365,25 +366,25 @@ impl TreeId { } macro_rules! mod_items { - ( $( $typ:ident in $fld:ident -> $ast:ty ),+ $(,)? ) => { + ($mod_item:ident -> $( $typ:ident in $fld:ident -> $ast:ty ),+ $(,)? ) => { #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] - pub enum ModItem { + pub(crate) enum $mod_item { $( $typ(FileAstId<$ast>), )+ } - impl ModItem { - pub fn ast_id(self) -> FileAstId { + impl $mod_item { + pub(crate) fn ast_id(self) -> FileAstId { match self { - $(ModItem::$typ(it) => it.upcast()),+ + $($mod_item::$typ(it) => it.upcast()),+ } } } $( - impl From> for ModItem { - fn from(id: FileAstId<$ast>) -> ModItem { + impl From> for $mod_item { + fn from(id: FileAstId<$ast>) -> $mod_item { ModItem::$typ(id) } } @@ -414,6 +415,7 @@ macro_rules! mod_items { } mod_items! { +ModItem -> Use in uses -> ast::Use, ExternCrate in extern_crates -> ast::ExternCrate, ExternBlock in extern_blocks -> ast::ExternBlock, @@ -539,7 +541,7 @@ pub struct ExternCrate { #[derive(Debug, Clone, Eq, PartialEq)] pub struct ExternBlock { pub ast_id: FileAstId, - pub children: Box<[ModItem]>, + pub(crate) children: Box<[ModItem]>, } #[derive(Debug, Clone, Eq, PartialEq)] @@ -647,12 +649,12 @@ pub struct TypeAlias { pub struct Mod { pub name: Name, pub visibility: RawVisibilityId, - pub kind: ModKind, + pub(crate) kind: ModKind, pub ast_id: FileAstId, } #[derive(Debug, Clone, Eq, PartialEq)] -pub enum ModKind { +pub(crate) enum ModKind { /// `mod m { ... }` Inline { items: Box<[ModItem]> }, /// `mod m;` diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index a8ee92d813..703cb79b55 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -35,8 +35,8 @@ use crate::{ db::DefDatabase, item_scope::{GlobId, ImportId, ImportOrExternCrate, PerNsGlobImports}, item_tree::{ - self, FieldsShape, ImportAlias, ImportKind, ItemTree, ItemTreeAstId, ItemTreeNode, Macro2, - MacroCall, MacroRules, Mod, ModItem, ModKind, TreeId, UseTreeKind, + self, AttrOwner, FieldsShape, ImportAlias, ImportKind, ItemTree, ItemTreeAstId, + ItemTreeNode, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, TreeId, UseTreeKind, }, macro_call_as_call_id, nameres::{ @@ -246,7 +246,7 @@ struct DefCollector<'a> { /// This also stores the attributes to skip when we resolve derive helpers and non-macro /// non-builtin attributes in general. // FIXME: There has to be a better way to do this - skip_attrs: FxHashMap, AttrId>, + skip_attrs: FxHashMap>, AttrId>, } impl DefCollector<'_> { @@ -472,7 +472,7 @@ impl DefCollector<'_> { attr.path().clone(), )); - self.skip_attrs.insert(ast_id.ast_id.with_value(*mod_item), attr.id); + self.skip_attrs.insert(ast_id.ast_id.with_value(mod_item.ast_id()), attr.id); Some((idx, directive, *mod_item, *tree)) } @@ -1371,7 +1371,9 @@ impl DefCollector<'_> { let mut recollect_without = |collector: &mut Self| { // Remove the original directive since we resolved it. let mod_dir = collector.mod_dirs[&directive.module_id].clone(); - collector.skip_attrs.insert(InFile::new(file_id, *mod_item), attr.id); + collector + .skip_attrs + .insert(InFile::new(file_id, mod_item.ast_id()), attr.id); let item_tree = tree.item_tree(self.db); ModCollector { @@ -1728,25 +1730,7 @@ impl ModCollector<'_, '_> { let attrs = self.item_tree.attrs(db, krate, item.into()); if let Some(cfg) = attrs.cfg() { if !self.is_cfg_enabled(&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(), - }; + let ast_id = item.ast_id().erase(); self.emit_unconfigured_diagnostic(InFile::new(self.file_id(), ast_id), &cfg); return; } @@ -2256,8 +2240,11 @@ impl ModCollector<'_, '_> { mod_item: ModItem, container: ItemContainerId, ) -> Result<(), ()> { - let mut ignore_up_to = - self.def_collector.skip_attrs.get(&InFile::new(self.file_id(), mod_item)).copied(); + let mut ignore_up_to = self + .def_collector + .skip_attrs + .get(&InFile::new(self.file_id(), mod_item.ast_id())) + .copied(); let iter = attrs .iter() .dedup_by(|a, b| { @@ -2309,7 +2296,7 @@ impl ModCollector<'_, '_> { fn collect_macro_rules(&mut self, id: ItemTreeAstId, module: ModuleId) { let krate = self.def_collector.def_map.krate; let mac = &self.item_tree[id]; - let attrs = self.item_tree.attrs(self.def_collector.db, krate, ModItem::from(id).into()); + let attrs = self.item_tree.attrs(self.def_collector.db, krate, AttrOwner::Item(id.erase())); let ast_id = InFile::new(self.file_id(), mac.ast_id.upcast()); let export_attr = || attrs.by_key(sym::macro_export); @@ -2398,7 +2385,7 @@ impl ModCollector<'_, '_> { // Case 1: builtin macros let mut helpers_opt = None; - let attrs = self.item_tree.attrs(self.def_collector.db, krate, ModItem::from(id).into()); + let attrs = self.item_tree.attrs(self.def_collector.db, krate, AttrOwner::Item(id.erase())); let expander = if attrs.by_key(sym::rustc_builtin_macro).exists() { if let Some(expander) = find_builtin_macro(&mac.name) { match expander { From 8930c58d30ab18711659719c949768657407b552 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 12 Jun 2025 11:06:32 +0200 Subject: [PATCH 20/56] Coalesce item tree data maps --- crates/hir-def/src/item_tree.rs | 157 +++++++++--------------- crates/hir-def/src/item_tree/lower.rs | 63 ++++------ crates/hir-def/src/item_tree/pretty.rs | 41 ++++--- crates/hir-def/src/nameres/collector.rs | 58 ++++----- 4 files changed, 138 insertions(+), 181 deletions(-) diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs index 4b3890ae96..b295767399 100644 --- a/crates/hir-def/src/item_tree.rs +++ b/crates/hir-def/src/item_tree.rs @@ -89,11 +89,12 @@ impl fmt::Debug for RawVisibilityId { /// The item tree of a source file. #[derive(Debug, Default, Eq, PartialEq)] pub struct ItemTree { - top_level: SmallVec<[ModItem; 1]>, + top_level: SmallVec<[ModItemId; 1]>, // Consider splitting this into top level RawAttrs and the map? attrs: FxHashMap, - data: Option>, + vis: ItemVisibilities, + data: FxHashMap, ModItem>, } impl ItemTree { @@ -130,14 +131,15 @@ impl ItemTree { if let Some(attrs) = top_attrs { item_tree.attrs.insert(AttrOwner::TopLevel, attrs); } - if item_tree.data.is_none() && item_tree.top_level.is_empty() && item_tree.attrs.is_empty() + if item_tree.data.is_empty() && item_tree.top_level.is_empty() && item_tree.attrs.is_empty() { EMPTY .get_or_init(|| { Arc::new(ItemTree { top_level: SmallVec::new_const(), attrs: FxHashMap::default(), - data: None, + data: FxHashMap::default(), + vis: ItemVisibilities { arena: Box::new([]) }, }) }) .clone() @@ -156,14 +158,15 @@ impl ItemTree { let ctx = lower::Ctx::new(db, loc.ast_id.file_id); let mut item_tree = ctx.lower_block(&block); - if item_tree.data.is_none() && item_tree.top_level.is_empty() && item_tree.attrs.is_empty() + if item_tree.data.is_empty() && item_tree.top_level.is_empty() && item_tree.attrs.is_empty() { EMPTY .get_or_init(|| { Arc::new(ItemTree { top_level: SmallVec::new_const(), attrs: FxHashMap::default(), - data: None, + data: FxHashMap::default(), + vis: ItemVisibilities { arena: Box::new([]) }, }) }) .clone() @@ -175,7 +178,7 @@ impl ItemTree { /// Returns an iterator over all items located at the top level of the `HirFileId` this /// `ItemTree` was created from. - pub(crate) fn top_level_items(&self) -> &[ModItem] { + pub(crate) fn top_level_items(&self) -> &[ModItemId] { &self.top_level } @@ -200,74 +203,33 @@ impl ItemTree { /// /// For more detail, see [`ItemTreeDataStats`]. pub fn item_tree_stats(&self) -> ItemTreeDataStats { - match self.data { - Some(ref data) => ItemTreeDataStats { - traits: data.traits.len(), - impls: data.impls.len(), - mods: data.mods.len(), - macro_calls: data.macro_calls.len(), - macro_rules: data.macro_rules.len(), - }, - None => ItemTreeDataStats::default(), + let mut traits = 0; + let mut impls = 0; + let mut mods = 0; + let mut macro_calls = 0; + let mut macro_rules = 0; + for item in self.data.values() { + match item { + ModItem::Trait(_) => traits += 1, + ModItem::Impl(_) => impls += 1, + ModItem::Mod(_) => mods += 1, + ModItem::MacroCall(_) => macro_calls += 1, + ModItem::MacroRules(_) => macro_rules += 1, + _ => {} + } } + ItemTreeDataStats { traits, impls, mods, macro_calls, macro_rules } } pub fn pretty_print(&self, db: &dyn DefDatabase, edition: Edition) -> String { pretty::print_item_tree(db, self, edition) } - fn data(&self) -> &ItemTreeData { - self.data.as_ref().expect("attempted to access data of empty ItemTree") - } - - fn data_mut(&mut self) -> &mut ItemTreeData { - self.data.get_or_insert_with(Box::default) - } - fn shrink_to_fit(&mut self) { - let ItemTree { top_level, attrs, data } = self; + let ItemTree { top_level, attrs, data, vis: _ } = self; top_level.shrink_to_fit(); attrs.shrink_to_fit(); - if let Some(data) = data { - let ItemTreeData { - uses, - extern_crates, - extern_blocks, - functions, - structs, - unions, - enums, - consts, - statics, - traits, - trait_aliases, - impls, - type_aliases, - mods, - macro_calls, - macro_rules, - macro_defs, - vis: _, - } = &mut **data; - - uses.shrink_to_fit(); - extern_crates.shrink_to_fit(); - extern_blocks.shrink_to_fit(); - functions.shrink_to_fit(); - structs.shrink_to_fit(); - unions.shrink_to_fit(); - enums.shrink_to_fit(); - consts.shrink_to_fit(); - statics.shrink_to_fit(); - traits.shrink_to_fit(); - trait_aliases.shrink_to_fit(); - impls.shrink_to_fit(); - type_aliases.shrink_to_fit(); - mods.shrink_to_fit(); - macro_calls.shrink_to_fit(); - macro_rules.shrink_to_fit(); - macro_defs.shrink_to_fit(); - } + data.shrink_to_fit(); } } @@ -276,29 +238,26 @@ struct ItemVisibilities { arena: Box<[RawVisibility]>, } -#[derive(Default, Debug, Eq, PartialEq)] -struct ItemTreeData { - uses: FxHashMap, Use>, - extern_crates: FxHashMap, ExternCrate>, - extern_blocks: FxHashMap, ExternBlock>, - functions: FxHashMap, Function>, - structs: FxHashMap, Struct>, - unions: FxHashMap, Union>, - enums: FxHashMap, Enum>, - consts: FxHashMap, Const>, - statics: FxHashMap, Static>, - traits: FxHashMap, Trait>, - trait_aliases: FxHashMap, TraitAlias>, - impls: FxHashMap, Impl>, - type_aliases: FxHashMap, TypeAlias>, - mods: FxHashMap, Mod>, - macro_calls: FxHashMap, MacroCall>, - macro_rules: FxHashMap, MacroRules>, - macro_defs: FxHashMap, Macro2>, - - vis: ItemVisibilities, +#[derive(Debug, Clone, Eq, PartialEq)] +enum ModItem { + Const(Const), + Enum(Enum), + ExternBlock(ExternBlock), + ExternCrate(ExternCrate), + Function(Function), + Impl(Impl), + Macro2(Macro2), + MacroCall(MacroCall), + MacroRules(MacroRules), + Mod(Mod), + Static(Static), + Struct(Struct), + Trait(Trait), + TraitAlias(TraitAlias), + TypeAlias(TypeAlias), + Union(Union), + Use(Use), } - #[derive(Default, Debug, Eq, PartialEq)] pub struct ItemTreeDataStats { pub traits: usize, @@ -316,9 +275,9 @@ pub enum AttrOwner { TopLevel, } -impl From for AttrOwner { +impl From for AttrOwner { #[inline] - fn from(value: ModItem) -> Self { + fn from(value: ModItemId) -> Self { AttrOwner::Item(value.ast_id().erase()) } } @@ -385,7 +344,7 @@ macro_rules! mod_items { $( impl From> for $mod_item { fn from(id: FileAstId<$ast>) -> $mod_item { - ModItem::$typ(id) + ModItemId::$typ(id) } } )+ @@ -399,7 +358,10 @@ macro_rules! mod_items { } fn lookup(tree: &ItemTree, index: FileAstId<$ast>) -> &Self { - &tree.data().$fld[&index] + match &tree.data[&index.upcast()] { + ModItem::$typ(item) => item, + _ => panic!("expected item of type `{}` at index `{:?}`", stringify!($typ), index), + } } } @@ -407,7 +369,10 @@ macro_rules! mod_items { type Output = $typ; fn index(&self, index: FileAstId<$ast>) -> &Self::Output { - &self.data().$fld[&index] + match &self.data[&index.upcast()] { + ModItem::$typ(item) => item, + _ => panic!("expected item of type `{}` at index `{:?}`", stringify!($typ), index), + } } } )+ @@ -415,7 +380,7 @@ macro_rules! mod_items { } mod_items! { -ModItem -> +ModItemId -> Use in uses -> ast::Use, ExternCrate in extern_crates -> ast::ExternCrate, ExternBlock in extern_blocks -> ast::ExternBlock, @@ -463,7 +428,7 @@ impl Index for ItemTree { VisibilityExplicitness::Explicit, ) }), - _ => &self.data().vis.arena[index.0 as usize], + _ => &self.vis.arena[index.0 as usize], } } } @@ -541,7 +506,7 @@ pub struct ExternCrate { #[derive(Debug, Clone, Eq, PartialEq)] pub struct ExternBlock { pub ast_id: FileAstId, - pub(crate) children: Box<[ModItem]>, + pub(crate) children: Box<[ModItemId]>, } #[derive(Debug, Clone, Eq, PartialEq)] @@ -656,7 +621,7 @@ pub struct Mod { #[derive(Debug, Clone, Eq, PartialEq)] pub(crate) enum ModKind { /// `mod m { ... }` - Inline { items: Box<[ModItem]> }, + Inline { items: Box<[ModItemId]> }, /// `mod m;` Outline, } diff --git a/crates/hir-def/src/item_tree/lower.rs b/crates/hir-def/src/item_tree/lower.rs index 17b115b6ec..f3e71effe4 100644 --- a/crates/hir-def/src/item_tree/lower.rs +++ b/crates/hir-def/src/item_tree/lower.rs @@ -21,10 +21,9 @@ use crate::{ db::DefDatabase, item_tree::{ AttrOwner, Const, Enum, ExternBlock, ExternCrate, FieldsShape, Function, Impl, ImportAlias, - Interned, ItemTree, ItemTreeAstId, ItemTreeData, Macro2, MacroCall, MacroRules, Mod, - ModItem, ModKind, ModPath, RawAttrs, RawVisibility, RawVisibilityId, Static, Struct, - StructKind, Trait, TraitAlias, TypeAlias, Union, Use, UseTree, UseTreeKind, - VisibilityExplicitness, + Interned, ItemTree, ItemTreeAstId, Macro2, MacroCall, MacroRules, Mod, ModItem, ModItemId, + ModKind, ModPath, RawAttrs, RawVisibility, RawVisibilityId, Static, Struct, StructKind, + Trait, TraitAlias, TypeAlias, Union, Use, UseTree, UseTreeKind, VisibilityExplicitness, }, }; @@ -56,9 +55,7 @@ impl<'a> Ctx<'a> { pub(super) fn lower_module_items(mut self, item_owner: &dyn HasModuleItem) -> ItemTree { self.tree.top_level = item_owner.items().flat_map(|item| self.lower_mod_item(&item)).collect(); - if let Some(data) = &mut self.tree.data { - data.vis.arena = self.visibilities.into_iter().collect(); - } + self.tree.vis.arena = self.visibilities.into_iter().collect(); self.tree } @@ -92,9 +89,7 @@ impl<'a> Ctx<'a> { } } - if let Some(data) = &mut self.tree.data { - data.vis.arena = self.visibilities.into_iter().collect(); - } + self.tree.vis.arena = self.visibilities.into_iter().collect(); self.tree } @@ -120,18 +115,12 @@ impl<'a> Ctx<'a> { } } } - if let Some(data) = &mut self.tree.data { - data.vis.arena = self.visibilities.into_iter().collect(); - } + self.tree.vis.arena = self.visibilities.into_iter().collect(); self.tree } - fn data(&mut self) -> &mut ItemTreeData { - self.tree.data_mut() - } - - fn lower_mod_item(&mut self, item: &ast::Item) -> Option { - let mod_item: ModItem = match item { + fn lower_mod_item(&mut self, item: &ast::Item) -> Option { + let mod_item: ModItemId = match item { ast::Item::Struct(ast) => self.lower_struct(ast)?.into(), ast::Item::Union(ast) => self.lower_union(ast)?.into(), ast::Item::Enum(ast) => self.lower_enum(ast)?.into(), @@ -175,7 +164,7 @@ impl<'a> Ctx<'a> { let ast_id = self.source_ast_id_map.ast_id(strukt); let shape = adt_shape(strukt.kind()); let res = Struct { name, visibility, shape, ast_id }; - self.data().structs.insert(ast_id, res); + self.tree.data.insert(ast_id.upcast(), ModItem::Struct(res)); Some(ast_id) } @@ -185,7 +174,7 @@ impl<'a> Ctx<'a> { let name = union.name()?.as_name(); let ast_id = self.source_ast_id_map.ast_id(union); let res = Union { name, visibility, ast_id }; - self.data().unions.insert(ast_id, res); + self.tree.data.insert(ast_id.upcast(), ModItem::Union(res)); Some(ast_id) } @@ -194,7 +183,7 @@ impl<'a> Ctx<'a> { let name = enum_.name()?.as_name(); let ast_id = self.source_ast_id_map.ast_id(enum_); let res = Enum { name, visibility, ast_id }; - self.data().enums.insert(ast_id, res); + self.tree.data.insert(ast_id.upcast(), ModItem::Enum(res)); Some(ast_id) } @@ -206,7 +195,7 @@ impl<'a> Ctx<'a> { let res = Function { name, visibility, ast_id }; - self.data().functions.insert(ast_id, res); + self.tree.data.insert(ast_id.upcast(), ModItem::Function(res)); Some(ast_id) } @@ -218,7 +207,7 @@ impl<'a> Ctx<'a> { let visibility = self.lower_visibility(type_alias); let ast_id = self.source_ast_id_map.ast_id(type_alias); let res = TypeAlias { name, visibility, ast_id }; - self.data().type_aliases.insert(ast_id, res); + self.tree.data.insert(ast_id.upcast(), ModItem::TypeAlias(res)); Some(ast_id) } @@ -227,7 +216,7 @@ impl<'a> Ctx<'a> { let visibility = self.lower_visibility(static_); let ast_id = self.source_ast_id_map.ast_id(static_); let res = Static { name, visibility, ast_id }; - self.data().statics.insert(ast_id, res); + self.tree.data.insert(ast_id.upcast(), ModItem::Static(res)); Some(ast_id) } @@ -236,7 +225,7 @@ impl<'a> Ctx<'a> { let visibility = self.lower_visibility(konst); let ast_id = self.source_ast_id_map.ast_id(konst); let res = Const { name, visibility, ast_id }; - self.data().consts.insert(ast_id, res); + self.tree.data.insert(ast_id.upcast(), ModItem::Const(res)); ast_id } @@ -258,7 +247,7 @@ impl<'a> Ctx<'a> { }; let ast_id = self.source_ast_id_map.ast_id(module); let res = Mod { name, visibility, kind, ast_id }; - self.data().mods.insert(ast_id, res); + self.tree.data.insert(ast_id.upcast(), ModItem::Mod(res)); Some(ast_id) } @@ -268,7 +257,7 @@ impl<'a> Ctx<'a> { let ast_id = self.source_ast_id_map.ast_id(trait_def); let def = Trait { name, visibility, ast_id }; - self.data().traits.insert(ast_id, def); + self.tree.data.insert(ast_id.upcast(), ModItem::Trait(def)); Some(ast_id) } @@ -281,7 +270,7 @@ impl<'a> Ctx<'a> { let ast_id = self.source_ast_id_map.ast_id(trait_alias_def); let alias = TraitAlias { name, visibility, ast_id }; - self.data().trait_aliases.insert(ast_id, alias); + self.tree.data.insert(ast_id.upcast(), ModItem::TraitAlias(alias)); Some(ast_id) } @@ -290,7 +279,7 @@ impl<'a> Ctx<'a> { // 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 { ast_id }; - self.data().impls.insert(ast_id, res); + self.tree.data.insert(ast_id.upcast(), ModItem::Impl(res)); ast_id } @@ -302,7 +291,7 @@ impl<'a> Ctx<'a> { })?; let res = Use { visibility, ast_id, use_tree }; - self.data().uses.insert(ast_id, res); + self.tree.data.insert(ast_id.upcast(), ModItem::Use(res)); Some(ast_id) } @@ -318,7 +307,7 @@ impl<'a> Ctx<'a> { let ast_id = self.source_ast_id_map.ast_id(extern_crate); let res = ExternCrate { name, alias, visibility, ast_id }; - self.data().extern_crates.insert(ast_id, res); + self.tree.data.insert(ast_id.upcast(), ModItem::ExternCrate(res)); Some(ast_id) } @@ -332,7 +321,7 @@ impl<'a> Ctx<'a> { let ast_id = self.source_ast_id_map.ast_id(m); let expand_to = hir_expand::ExpandTo::from_call_site(m); let res = MacroCall { path, ast_id, expand_to, ctxt: span_map.span_for_range(range).ctx }; - self.data().macro_calls.insert(ast_id, res); + self.tree.data.insert(ast_id.upcast(), ModItem::MacroCall(res)); Some(ast_id) } @@ -341,7 +330,7 @@ impl<'a> Ctx<'a> { let ast_id = self.source_ast_id_map.ast_id(m); let res = MacroRules { name: name.as_name(), ast_id }; - self.data().macro_rules.insert(ast_id, res); + self.tree.data.insert(ast_id.upcast(), ModItem::MacroRules(res)); Some(ast_id) } @@ -352,7 +341,7 @@ impl<'a> Ctx<'a> { let visibility = self.lower_visibility(m); let res = Macro2 { name: name.as_name(), ast_id, visibility }; - self.data().macro_defs.insert(ast_id, res); + self.tree.data.insert(ast_id.upcast(), ModItem::Macro2(res)); Some(ast_id) } @@ -365,7 +354,7 @@ impl<'a> Ctx<'a> { // (in other words, the knowledge that they're in an extern block must not be used). // This is because an extern block can contain macros whose ItemTree's top-level items // should be considered to be in an extern block too. - let mod_item: ModItem = match &item { + let mod_item: ModItemId = match &item { ast::ExternItem::Fn(ast) => self.lower_function(ast)?.into(), ast::ExternItem::Static(ast) => self.lower_static(ast)?.into(), ast::ExternItem::TypeAlias(ty) => self.lower_type_alias(ty)?.into(), @@ -379,7 +368,7 @@ impl<'a> Ctx<'a> { }); let res = ExternBlock { ast_id, children }; - self.data().extern_blocks.insert(ast_id, res); + self.tree.data.insert(ast_id.upcast(), ModItem::ExternBlock(res)); ast_id } diff --git a/crates/hir-def/src/item_tree/pretty.rs b/crates/hir-def/src/item_tree/pretty.rs index 0c62b86dae..9a5ca73836 100644 --- a/crates/hir-def/src/item_tree/pretty.rs +++ b/crates/hir-def/src/item_tree/pretty.rs @@ -7,8 +7,9 @@ use span::{Edition, ErasedFileAstId}; use crate::{ item_tree::{ 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, + ItemTree, Macro2, MacroCall, MacroRules, Mod, ModItemId, ModKind, RawAttrs, + RawVisibilityId, Static, Struct, Trait, TraitAlias, TypeAlias, Union, Use, UseTree, + UseTreeKind, }, visibility::RawVisibility, }; @@ -159,11 +160,11 @@ impl Printer<'_> { } } - fn print_mod_item(&mut self, item: ModItem) { + fn print_mod_item(&mut self, item: ModItemId) { self.print_attrs_of(item, "\n"); match item { - ModItem::Use(it) => { + ModItemId::Use(it) => { let Use { visibility, use_tree, ast_id } = &self.tree[it]; self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); @@ -171,7 +172,7 @@ impl Printer<'_> { self.print_use_tree(use_tree); wln!(self, ";"); } - ModItem::ExternCrate(it) => { + ModItemId::ExternCrate(it) => { let ExternCrate { name, alias, visibility, ast_id } = &self.tree[it]; self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); @@ -181,7 +182,7 @@ impl Printer<'_> { } wln!(self, ";"); } - ModItem::ExternBlock(it) => { + ModItemId::ExternBlock(it) => { let ExternBlock { ast_id, children } = &self.tree[it]; self.print_ast_id(ast_id.erase()); w!(self, "extern {{"); @@ -192,13 +193,13 @@ impl Printer<'_> { }); wln!(self, "}}"); } - ModItem::Function(it) => { + ModItemId::Function(it) => { let Function { name, visibility, ast_id } = &self.tree[it]; self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); wln!(self, "fn {};", name.display(self.db, self.edition)); } - ModItem::Struct(it) => { + ModItemId::Struct(it) => { let Struct { visibility, name, shape: kind, ast_id } = &self.tree[it]; self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); @@ -210,7 +211,7 @@ impl Printer<'_> { wln!(self, ";"); } } - ModItem::Union(it) => { + ModItemId::Union(it) => { let Union { name, visibility, ast_id } = &self.tree[it]; self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); @@ -218,13 +219,13 @@ impl Printer<'_> { self.print_fields(FieldsShape::Record); wln!(self); } - ModItem::Enum(it) => { + ModItemId::Enum(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)); } - ModItem::Const(it) => { + ModItemId::Const(it) => { let Const { name, visibility, ast_id } = &self.tree[it]; self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); @@ -235,7 +236,7 @@ impl Printer<'_> { } wln!(self, " = _;"); } - ModItem::Static(it) => { + ModItemId::Static(it) => { let Static { name, visibility, ast_id } = &self.tree[it]; self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); @@ -244,24 +245,24 @@ impl Printer<'_> { w!(self, " = _;"); wln!(self); } - ModItem::Trait(it) => { + ModItemId::Trait(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)); } - ModItem::TraitAlias(it) => { + ModItemId::TraitAlias(it) => { let TraitAlias { name, visibility, ast_id } = &self.tree[it]; self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); wln!(self, "trait {} = ..;", name.display(self.db, self.edition)); } - ModItem::Impl(it) => { + ModItemId::Impl(it) => { let Impl { ast_id } = &self.tree[it]; self.print_ast_id(ast_id.erase()); w!(self, "impl {{ ... }}"); } - ModItem::TypeAlias(it) => { + ModItemId::TypeAlias(it) => { let TypeAlias { name, visibility, ast_id } = &self.tree[it]; self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); @@ -269,7 +270,7 @@ impl Printer<'_> { w!(self, ";"); wln!(self); } - ModItem::Mod(it) => { + ModItemId::Mod(it) => { let Mod { name, visibility, kind, ast_id } = &self.tree[it]; self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); @@ -289,7 +290,7 @@ impl Printer<'_> { } } } - ModItem::MacroCall(it) => { + ModItemId::MacroCall(it) => { let MacroCall { path, ast_id, expand_to, ctxt } = &self.tree[it]; let _ = writeln!( self, @@ -300,12 +301,12 @@ impl Printer<'_> { ); wln!(self, "{}!(...);", path.display(self.db, self.edition)); } - ModItem::MacroRules(it) => { + ModItemId::MacroRules(it) => { let MacroRules { name, ast_id } = &self.tree[it]; self.print_ast_id(ast_id.erase()); wln!(self, "macro_rules! {} {{ ... }}", name.display(self.db, self.edition)); } - ModItem::Macro2(it) => { + ModItemId::Macro2(it) => { let Macro2 { name, visibility, ast_id } = &self.tree[it]; self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index 703cb79b55..3dc76dcb8f 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -36,7 +36,7 @@ use crate::{ item_scope::{GlobId, ImportId, ImportOrExternCrate, PerNsGlobImports}, item_tree::{ self, AttrOwner, FieldsShape, ImportAlias, ImportKind, ItemTree, ItemTreeAstId, - ItemTreeNode, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, TreeId, UseTreeKind, + ItemTreeNode, Macro2, MacroCall, MacroRules, Mod, ModItemId, ModKind, TreeId, UseTreeKind, }, macro_call_as_call_id, nameres::{ @@ -208,7 +208,7 @@ enum MacroDirectiveKind { Attr { ast_id: AstIdWithPath, attr: Attr, - mod_item: ModItem, + mod_item: ModItemId, /* is this needed? */ tree: TreeId, }, } @@ -1436,9 +1436,9 @@ impl DefCollector<'_> { let item_tree = tree.item_tree(self.db); let ast_adt_id: FileAstId = match *mod_item { - ModItem::Struct(strukt) => item_tree[strukt].ast_id().upcast(), - ModItem::Union(union) => item_tree[union].ast_id().upcast(), - ModItem::Enum(enum_) => item_tree[enum_].ast_id().upcast(), + ModItemId::Struct(strukt) => item_tree[strukt].ast_id().upcast(), + ModItemId::Union(union) => item_tree[union].ast_id().upcast(), + ModItemId::Enum(enum_) => item_tree[enum_].ast_id().upcast(), _ => { let diag = DefDiagnostic::invalid_derive_target( directive.module_id, @@ -1682,12 +1682,12 @@ struct ModCollector<'a, 'b> { } impl ModCollector<'_, '_> { - fn collect_in_top_module(&mut self, items: &[ModItem]) { + fn collect_in_top_module(&mut self, items: &[ModItemId]) { let module = self.def_collector.def_map.module_id(self.module_id); self.collect(items, module.into()) } - fn collect(&mut self, items: &[ModItem], container: ItemContainerId) { + fn collect(&mut self, items: &[ModItemId], container: ItemContainerId) { let krate = self.def_collector.def_map.krate; let is_crate_root = self.module_id == DefMap::ROOT && self.def_collector.def_map.block.is_none(); @@ -1726,7 +1726,7 @@ impl ModCollector<'_, '_> { .unwrap_or(Visibility::Public) }; - let mut process_mod_item = |item: ModItem| { + let mut process_mod_item = |item: ModItemId| { let attrs = self.item_tree.attrs(db, krate, item.into()); if let Some(cfg) = attrs.cfg() { if !self.is_cfg_enabled(&cfg) { @@ -1748,8 +1748,8 @@ impl ModCollector<'_, '_> { self.def_collector.crate_local_def_map.unwrap_or(&self.def_collector.local_def_map); match item { - ModItem::Mod(m) => self.collect_module(m, &attrs), - ModItem::Use(item_tree_id) => { + ModItemId::Mod(m) => self.collect_module(m, &attrs), + ModItemId::Use(item_tree_id) => { let id = UseLoc { container: module, id: InFile::new(self.file_id(), self.item_tree[item_tree_id].ast_id), @@ -1771,7 +1771,7 @@ impl ModCollector<'_, '_> { }, ) } - ModItem::ExternCrate(item_tree_id) => { + ModItemId::ExternCrate(item_tree_id) => { let item_tree::ExternCrate { name, visibility, alias, ast_id } = &self.item_tree[item_tree_id]; @@ -1845,7 +1845,7 @@ impl ModCollector<'_, '_> { ); } } - ModItem::ExternBlock(block) => { + ModItemId::ExternBlock(block) => { let extern_block_id = ExternBlockLoc { container: module, id: InFile::new(self.file_id(), self.item_tree[block].ast_id), @@ -1859,10 +1859,12 @@ impl ModCollector<'_, '_> { ItemContainerId::ExternBlockId(extern_block_id), ) } - ModItem::MacroCall(mac) => self.collect_macro_call(&self.item_tree[mac], container), - ModItem::MacroRules(id) => self.collect_macro_rules(id, module), - ModItem::Macro2(id) => self.collect_macro_def(id, module), - ModItem::Impl(imp) => { + ModItemId::MacroCall(mac) => { + self.collect_macro_call(&self.item_tree[mac], container) + } + ModItemId::MacroRules(id) => self.collect_macro_rules(id, module), + ModItemId::Macro2(id) => self.collect_macro_def(id, module), + ModItemId::Impl(imp) => { let impl_id = ImplLoc { container: module, id: InFile::new(self.file_id(), self.item_tree[imp].ast_id), @@ -1870,7 +1872,7 @@ impl ModCollector<'_, '_> { .intern(db); self.def_collector.def_map.modules[self.module_id].scope.define_impl(impl_id) } - ModItem::Function(id) => { + ModItemId::Function(id) => { let it = &self.item_tree[id]; let fn_id = FunctionLoc { container, @@ -1895,7 +1897,7 @@ impl ModCollector<'_, '_> { update_def(self.def_collector, fn_id.into(), &it.name, vis, false); } - ModItem::Struct(id) => { + ModItemId::Struct(id) => { let it = &self.item_tree[id]; let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]); @@ -1909,7 +1911,7 @@ impl ModCollector<'_, '_> { !matches!(it.shape, FieldsShape::Record), ); } - ModItem::Union(id) => { + ModItemId::Union(id) => { let it = &self.item_tree[id]; let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]); @@ -1923,7 +1925,7 @@ impl ModCollector<'_, '_> { false, ); } - ModItem::Enum(id) => { + ModItemId::Enum(id) => { let it = &self.item_tree[id]; let enum_ = EnumLoc { container: module, @@ -1934,7 +1936,7 @@ impl ModCollector<'_, '_> { 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); } - ModItem::Const(id) => { + ModItemId::Const(id) => { let it = &self.item_tree[id]; let const_id = ConstLoc { container, id: InFile::new(self.tree_id.file_id(), it.ast_id) } @@ -1954,7 +1956,7 @@ impl ModCollector<'_, '_> { } } } - ModItem::Static(id) => { + ModItemId::Static(id) => { let it = &self.item_tree[id]; let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]); @@ -1968,7 +1970,7 @@ impl ModCollector<'_, '_> { false, ); } - ModItem::Trait(id) => { + ModItemId::Trait(id) => { let it = &self.item_tree[id]; let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]); @@ -1982,7 +1984,7 @@ impl ModCollector<'_, '_> { false, ); } - ModItem::TraitAlias(id) => { + ModItemId::TraitAlias(id) => { let it = &self.item_tree[id]; let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]); @@ -1999,7 +2001,7 @@ impl ModCollector<'_, '_> { false, ); } - ModItem::TypeAlias(id) => { + ModItemId::TypeAlias(id) => { let it = &self.item_tree[id]; let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]); @@ -2022,12 +2024,12 @@ impl ModCollector<'_, '_> { if is_crate_root { items .iter() - .filter(|it| matches!(it, ModItem::ExternCrate(..))) + .filter(|it| matches!(it, ModItemId::ExternCrate(..))) .copied() .for_each(&mut process_mod_item); items .iter() - .filter(|it| !matches!(it, ModItem::ExternCrate(..))) + .filter(|it| !matches!(it, ModItemId::ExternCrate(..))) .copied() .for_each(process_mod_item); } else { @@ -2237,7 +2239,7 @@ impl ModCollector<'_, '_> { fn resolve_attributes( &mut self, attrs: &Attrs, - mod_item: ModItem, + mod_item: ModItemId, container: ItemContainerId, ) -> Result<(), ()> { let mut ignore_up_to = self From f27268f319d402fcd68509e1836edaea8dc357ea Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 12 Jun 2025 11:25:20 +0200 Subject: [PATCH 21/56] Ditch the unnecessary smallvec --- crates/hir-def/src/item_tree.rs | 11 +++++------ crates/hir-def/src/item_tree/lower.rs | 16 ++++++++++------ 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs index b295767399..9f8d7b9e31 100644 --- a/crates/hir-def/src/item_tree.rs +++ b/crates/hir-def/src/item_tree.rs @@ -53,7 +53,6 @@ use hir_expand::{ use intern::Interned; use la_arena::Idx; use rustc_hash::FxHashMap; -use smallvec::SmallVec; use span::{AstIdNode, Edition, ErasedFileAstId, FileAstId, SyntaxContext}; use stdx::never; use syntax::{SyntaxKind, ast, match_ast}; @@ -89,11 +88,12 @@ impl fmt::Debug for RawVisibilityId { /// The item tree of a source file. #[derive(Debug, Default, Eq, PartialEq)] pub struct ItemTree { - top_level: SmallVec<[ModItemId; 1]>, + top_level: Box<[ModItemId]>, // Consider splitting this into top level RawAttrs and the map? attrs: FxHashMap, vis: ItemVisibilities, + // FIXME: They values store the key, turn this into a FxHashSet instead? data: FxHashMap, ModItem>, } @@ -136,7 +136,7 @@ impl ItemTree { EMPTY .get_or_init(|| { Arc::new(ItemTree { - top_level: SmallVec::new_const(), + top_level: Box::new([]), attrs: FxHashMap::default(), data: FxHashMap::default(), vis: ItemVisibilities { arena: Box::new([]) }, @@ -163,7 +163,7 @@ impl ItemTree { EMPTY .get_or_init(|| { Arc::new(ItemTree { - top_level: SmallVec::new_const(), + top_level: Box::new([]), attrs: FxHashMap::default(), data: FxHashMap::default(), vis: ItemVisibilities { arena: Box::new([]) }, @@ -226,8 +226,7 @@ impl ItemTree { } fn shrink_to_fit(&mut self) { - let ItemTree { top_level, attrs, data, vis: _ } = self; - top_level.shrink_to_fit(); + let ItemTree { top_level: _, attrs, data, vis: _ } = self; attrs.shrink_to_fit(); data.shrink_to_fit(); } diff --git a/crates/hir-def/src/item_tree/lower.rs b/crates/hir-def/src/item_tree/lower.rs index f3e71effe4..a7038356b3 100644 --- a/crates/hir-def/src/item_tree/lower.rs +++ b/crates/hir-def/src/item_tree/lower.rs @@ -33,6 +33,7 @@ pub(super) struct Ctx<'a> { source_ast_id_map: Arc, span_map: OnceCell, file: HirFileId, + top_level: Vec, visibilities: FxIndexSet, } @@ -45,6 +46,7 @@ impl<'a> Ctx<'a> { file, span_map: OnceCell::new(), visibilities: FxIndexSet::default(), + top_level: Vec::new(), } } @@ -53,14 +55,14 @@ impl<'a> Ctx<'a> { } pub(super) fn lower_module_items(mut self, item_owner: &dyn HasModuleItem) -> ItemTree { - self.tree.top_level = - item_owner.items().flat_map(|item| self.lower_mod_item(&item)).collect(); + self.top_level = item_owner.items().flat_map(|item| self.lower_mod_item(&item)).collect(); self.tree.vis.arena = self.visibilities.into_iter().collect(); + self.tree.top_level = self.top_level.into_boxed_slice(); self.tree } pub(super) fn lower_macro_stmts(mut self, stmts: ast::MacroStmts) -> ItemTree { - self.tree.top_level = stmts + self.top_level = stmts .statements() .filter_map(|stmt| { match stmt { @@ -84,18 +86,19 @@ impl<'a> Ctx<'a> { if let Some(call) = tail_macro.macro_call() { cov_mark::hit!(macro_stmt_with_trailing_macro_expr); if let Some(mod_item) = self.lower_mod_item(&call.into()) { - self.tree.top_level.push(mod_item); + self.top_level.push(mod_item); } } } self.tree.vis.arena = self.visibilities.into_iter().collect(); + self.tree.top_level = self.top_level.into_boxed_slice(); self.tree } pub(super) fn lower_block(mut self, block: &ast::BlockExpr) -> ItemTree { self.tree.attrs.insert(AttrOwner::TopLevel, RawAttrs::new(self.db, block, self.span_map())); - self.tree.top_level = block + self.top_level = block .statements() .filter_map(|stmt| match stmt { ast::Stmt::Item(item) => self.lower_mod_item(&item), @@ -111,11 +114,12 @@ impl<'a> Ctx<'a> { if let Some(ast::Expr::MacroExpr(expr)) = block.tail_expr() { if let Some(call) = expr.macro_call() { if let Some(mod_item) = self.lower_mod_item(&call.into()) { - self.tree.top_level.push(mod_item); + self.top_level.push(mod_item); } } } self.tree.vis.arena = self.visibilities.into_iter().collect(); + self.tree.top_level = self.top_level.into_boxed_slice(); self.tree } From 83a7ecdeada09d26247189e304ab34e1fd30848d Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 12 Jun 2025 11:41:46 +0200 Subject: [PATCH 22/56] Remove `AttrOwner` --- crates/hir-def/src/attr.rs | 16 +++--- crates/hir-def/src/db.rs | 2 +- crates/hir-def/src/item_tree.rs | 68 ++++++++++++------------- crates/hir-def/src/item_tree/lower.rs | 18 +++---- crates/hir-def/src/item_tree/pretty.rs | 15 +++--- crates/hir-def/src/nameres/collector.rs | 10 ++-- 6 files changed, 60 insertions(+), 69 deletions(-) diff --git a/crates/hir-def/src/attr.rs b/crates/hir-def/src/attr.rs index 08986d68e5..d63bd391fd 100644 --- a/crates/hir-def/src/attr.rs +++ b/crates/hir-def/src/attr.rs @@ -26,7 +26,6 @@ use crate::{ AdtId, AstIdLoc, AttrDefId, GenericParamId, HasModule, LocalFieldId, Lookup, MacroId, VariantId, db::DefDatabase, - item_tree::AttrOwner, lang_item::LangItem, nameres::{ModuleOrigin, ModuleSource}, src::{HasChildSource, HasSource}, @@ -526,23 +525,22 @@ impl AttrsWithOwner { ModuleOrigin::File { definition, declaration_tree_id, declaration, .. } => { let decl_attrs = declaration_tree_id .item_tree(db) - .raw_attrs(AttrOwner::Item(declaration.erase())) + .raw_attrs(declaration.upcast()) .clone(); let tree = db.file_item_tree(definition.into()); - let def_attrs = tree.raw_attrs(AttrOwner::TopLevel).clone(); + let def_attrs = tree.top_level_raw_attrs().clone(); decl_attrs.merge(def_attrs) } ModuleOrigin::CrateRoot { definition } => { let tree = db.file_item_tree(definition.into()); - tree.raw_attrs(AttrOwner::TopLevel).clone() + tree.top_level_raw_attrs().clone() + } + ModuleOrigin::Inline { definition_tree_id, definition } => { + definition_tree_id.item_tree(db).raw_attrs(definition.upcast()).clone() } - ModuleOrigin::Inline { definition_tree_id, definition } => definition_tree_id - .item_tree(db) - .raw_attrs(AttrOwner::Item(definition.erase())) - .clone(), ModuleOrigin::BlockExpr { id, .. } => { let tree = db.block_item_tree(id); - tree.raw_attrs(AttrOwner::TopLevel).clone() + tree.top_level_raw_attrs().clone() } }; Attrs::expand_cfg_attr(db, module.krate, raw_attrs) diff --git a/crates/hir-def/src/db.rs b/crates/hir-def/src/db.rs index 95e33dde58..5f99693139 100644 --- a/crates/hir-def/src/db.rs +++ b/crates/hir-def/src/db.rs @@ -376,7 +376,7 @@ fn include_macro_invoc( fn crate_supports_no_std(db: &dyn DefDatabase, crate_id: Crate) -> bool { let file = crate_id.data(db).root_file_id(db); let item_tree = db.file_item_tree(file.into()); - let attrs = item_tree.raw_attrs(crate::item_tree::AttrOwner::TopLevel); + let attrs = item_tree.top_level_raw_attrs(); for attr in &**attrs { match attr.path().as_ident() { Some(ident) if *ident == sym::no_std => return true, diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs index 9f8d7b9e31..79f4b174e1 100644 --- a/crates/hir-def/src/item_tree.rs +++ b/crates/hir-def/src/item_tree.rs @@ -53,7 +53,7 @@ use hir_expand::{ use intern::Interned; use la_arena::Idx; use rustc_hash::FxHashMap; -use span::{AstIdNode, Edition, ErasedFileAstId, FileAstId, SyntaxContext}; +use span::{AstIdNode, Edition, FileAstId, SyntaxContext}; use stdx::never; use syntax::{SyntaxKind, ast, match_ast}; use triomphe::Arc; @@ -89,9 +89,8 @@ impl fmt::Debug for RawVisibilityId { #[derive(Debug, Default, Eq, PartialEq)] pub struct ItemTree { top_level: Box<[ModItemId]>, - // Consider splitting this into top level RawAttrs and the map? - attrs: FxHashMap, - + top_attrs: RawAttrs, + attrs: FxHashMap, RawAttrs>, vis: ItemVisibilities, // FIXME: They values store the key, turn this into a FxHashSet instead? data: FxHashMap, ModItem>, @@ -104,12 +103,13 @@ impl ItemTree { let ctx = lower::Ctx::new(db, file_id); let syntax = db.parse_or_expand(file_id); - let mut top_attrs = None; let mut item_tree = match_ast! { match syntax { ast::SourceFile(file) => { - top_attrs = Some(RawAttrs::new(db, &file, ctx.span_map())); - ctx.lower_module_items(&file) + let top_attrs = RawAttrs::new(db, &file, ctx.span_map()); + let mut item_tree = ctx.lower_module_items(&file); + item_tree.top_attrs = top_attrs; + item_tree }, ast::MacroItems(items) => { ctx.lower_module_items(&items) @@ -128,10 +128,10 @@ impl ItemTree { } }; - if let Some(attrs) = top_attrs { - item_tree.attrs.insert(AttrOwner::TopLevel, attrs); - } - if item_tree.data.is_empty() && item_tree.top_level.is_empty() && item_tree.attrs.is_empty() + if item_tree.data.is_empty() + && item_tree.top_level.is_empty() + && item_tree.attrs.is_empty() + && item_tree.top_attrs.is_empty() { EMPTY .get_or_init(|| { @@ -139,6 +139,7 @@ impl ItemTree { top_level: Box::new([]), attrs: FxHashMap::default(), data: FxHashMap::default(), + top_attrs: RawAttrs::EMPTY, vis: ItemVisibilities { arena: Box::new([]) }, }) }) @@ -158,7 +159,10 @@ impl ItemTree { let ctx = lower::Ctx::new(db, loc.ast_id.file_id); let mut item_tree = ctx.lower_block(&block); - if item_tree.data.is_empty() && item_tree.top_level.is_empty() && item_tree.attrs.is_empty() + if item_tree.data.is_empty() + && item_tree.top_level.is_empty() + && item_tree.attrs.is_empty() + && item_tree.top_attrs.is_empty() { EMPTY .get_or_init(|| { @@ -166,6 +170,7 @@ impl ItemTree { top_level: Box::new([]), attrs: FxHashMap::default(), data: FxHashMap::default(), + top_attrs: RawAttrs::EMPTY, vis: ItemVisibilities { arena: Box::new([]) }, }) }) @@ -183,19 +188,25 @@ impl ItemTree { } /// Returns the inner attributes of the source file. - pub fn top_level_attrs(&self, db: &dyn DefDatabase, krate: Crate) -> Attrs { - Attrs::expand_cfg_attr( - db, - krate, - self.attrs.get(&AttrOwner::TopLevel).unwrap_or(&RawAttrs::EMPTY).clone(), - ) + pub fn top_level_raw_attrs(&self) -> &RawAttrs { + &self.top_attrs } - pub(crate) fn raw_attrs(&self, of: AttrOwner) -> &RawAttrs { + /// Returns the inner attributes of the source file. + pub fn top_level_attrs(&self, db: &dyn DefDatabase, krate: Crate) -> Attrs { + Attrs::expand_cfg_attr(db, krate, self.top_attrs.clone()) + } + + pub(crate) fn raw_attrs(&self, of: FileAstId) -> &RawAttrs { self.attrs.get(&of).unwrap_or(&RawAttrs::EMPTY) } - pub(crate) fn attrs(&self, db: &dyn DefDatabase, krate: Crate, of: AttrOwner) -> Attrs { + pub(crate) fn attrs( + &self, + db: &dyn DefDatabase, + krate: Crate, + of: FileAstId, + ) -> Attrs { Attrs::expand_cfg_attr(db, krate, self.raw_attrs(of).clone()) } @@ -226,7 +237,7 @@ impl ItemTree { } fn shrink_to_fit(&mut self) { - let ItemTree { top_level: _, attrs, data, vis: _ } = self; + let ItemTree { top_level: _, attrs, data, vis: _, top_attrs: _ } = self; attrs.shrink_to_fit(); data.shrink_to_fit(); } @@ -266,21 +277,6 @@ pub struct ItemTreeDataStats { pub macro_rules: usize, } -#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] -pub enum AttrOwner { - /// Attributes on an item. - Item(ErasedFileAstId), - /// Inner attributes of the source file. - TopLevel, -} - -impl From for AttrOwner { - #[inline] - fn from(value: ModItemId) -> Self { - AttrOwner::Item(value.ast_id().erase()) - } -} - /// Trait implemented by all nodes in the item tree. pub trait ItemTreeNode: Clone { type Source: AstIdNode; diff --git a/crates/hir-def/src/item_tree/lower.rs b/crates/hir-def/src/item_tree/lower.rs index a7038356b3..c3089eef90 100644 --- a/crates/hir-def/src/item_tree/lower.rs +++ b/crates/hir-def/src/item_tree/lower.rs @@ -10,7 +10,7 @@ use hir_expand::{ span_map::{SpanMap, SpanMapRef}, }; use la_arena::Arena; -use span::{AstIdMap, SyntaxContext}; +use span::{AstIdMap, FileAstId, SyntaxContext}; use syntax::{ AstNode, ast::{self, HasModuleItem, HasName}, @@ -20,10 +20,10 @@ use triomphe::Arc; use crate::{ db::DefDatabase, item_tree::{ - AttrOwner, Const, Enum, ExternBlock, ExternCrate, FieldsShape, Function, Impl, ImportAlias, - Interned, ItemTree, ItemTreeAstId, Macro2, MacroCall, MacroRules, Mod, ModItem, ModItemId, - ModKind, ModPath, RawAttrs, RawVisibility, RawVisibilityId, Static, Struct, StructKind, - Trait, TraitAlias, TypeAlias, Union, Use, UseTree, UseTreeKind, VisibilityExplicitness, + Const, Enum, ExternBlock, ExternCrate, FieldsShape, Function, Impl, ImportAlias, Interned, + ItemTree, ItemTreeAstId, Macro2, MacroCall, MacroRules, Mod, ModItem, ModItemId, ModKind, + ModPath, RawAttrs, RawVisibility, RawVisibilityId, Static, Struct, StructKind, Trait, + TraitAlias, TypeAlias, Union, Use, UseTree, UseTreeKind, VisibilityExplicitness, }, }; @@ -97,7 +97,7 @@ impl<'a> Ctx<'a> { } pub(super) fn lower_block(mut self, block: &ast::BlockExpr) -> ItemTree { - self.tree.attrs.insert(AttrOwner::TopLevel, RawAttrs::new(self.db, block, self.span_map())); + self.tree.top_attrs = RawAttrs::new(self.db, block, self.span_map()); self.top_level = block .statements() .filter_map(|stmt| match stmt { @@ -144,12 +144,12 @@ impl<'a> Ctx<'a> { ast::Item::ExternBlock(ast) => self.lower_extern_block(ast).into(), }; let attrs = RawAttrs::new(self.db, item, self.span_map()); - self.add_attrs(mod_item.into(), attrs); + self.add_attrs(mod_item.ast_id(), attrs); Some(mod_item) } - fn add_attrs(&mut self, item: AttrOwner, attrs: RawAttrs) { + fn add_attrs(&mut self, item: FileAstId, attrs: RawAttrs) { if !attrs.is_empty() { match self.tree.attrs.entry(item) { Entry::Occupied(mut entry) => { @@ -365,7 +365,7 @@ impl<'a> Ctx<'a> { ast::ExternItem::MacroCall(call) => self.lower_macro_call(call)?.into(), }; let attrs = RawAttrs::new(self.db, &item, self.span_map()); - self.add_attrs(mod_item.into(), attrs); + self.add_attrs(mod_item.ast_id(), attrs); Some(mod_item) }) .collect() diff --git a/crates/hir-def/src/item_tree/pretty.rs b/crates/hir-def/src/item_tree/pretty.rs index 9a5ca73836..11b9156898 100644 --- a/crates/hir-def/src/item_tree/pretty.rs +++ b/crates/hir-def/src/item_tree/pretty.rs @@ -6,10 +6,9 @@ use span::{Edition, ErasedFileAstId}; use crate::{ item_tree::{ - AttrOwner, Const, DefDatabase, Enum, ExternBlock, ExternCrate, FieldsShape, Function, Impl, - ItemTree, Macro2, MacroCall, MacroRules, Mod, ModItemId, ModKind, RawAttrs, - RawVisibilityId, Static, Struct, Trait, TraitAlias, TypeAlias, Union, Use, UseTree, - UseTreeKind, + Const, DefDatabase, Enum, ExternBlock, ExternCrate, FieldsShape, Function, Impl, ItemTree, + Macro2, MacroCall, MacroRules, Mod, ModItemId, ModKind, RawAttrs, RawVisibilityId, Static, + Struct, Trait, TraitAlias, TypeAlias, Union, Use, UseTree, UseTreeKind, }, visibility::RawVisibility, }; @@ -18,9 +17,7 @@ pub(super) fn print_item_tree(db: &dyn DefDatabase, tree: &ItemTree, edition: Ed let mut p = Printer { db, tree, buf: String::new(), indent_level: 0, needs_indent: true, edition }; - if let Some(attrs) = tree.attrs.get(&AttrOwner::TopLevel) { - p.print_attrs(attrs, true, "\n"); - } + p.print_attrs(&tree.top_attrs, true, "\n"); p.blank(); for item in tree.top_level_items() { @@ -102,8 +99,8 @@ impl Printer<'_> { } } - fn print_attrs_of(&mut self, of: impl Into, separated_by: &str) { - if let Some(attrs) = self.tree.attrs.get(&of.into()) { + fn print_attrs_of(&mut self, of: ModItemId, separated_by: &str) { + if let Some(attrs) = self.tree.attrs.get(&of.ast_id()) { self.print_attrs(attrs, false, separated_by); } } diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index 3dc76dcb8f..a6be3f1fbf 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -35,8 +35,8 @@ use crate::{ db::DefDatabase, item_scope::{GlobId, ImportId, ImportOrExternCrate, PerNsGlobImports}, item_tree::{ - self, AttrOwner, FieldsShape, ImportAlias, ImportKind, ItemTree, ItemTreeAstId, - ItemTreeNode, Macro2, MacroCall, MacroRules, Mod, ModItemId, ModKind, TreeId, UseTreeKind, + self, FieldsShape, ImportAlias, ImportKind, ItemTree, ItemTreeAstId, ItemTreeNode, Macro2, + MacroCall, MacroRules, Mod, ModItemId, ModKind, TreeId, UseTreeKind, }, macro_call_as_call_id, nameres::{ @@ -1727,7 +1727,7 @@ impl ModCollector<'_, '_> { }; let mut process_mod_item = |item: ModItemId| { - let attrs = self.item_tree.attrs(db, krate, item.into()); + let attrs = self.item_tree.attrs(db, krate, item.ast_id()); if let Some(cfg) = attrs.cfg() { if !self.is_cfg_enabled(&cfg) { let ast_id = item.ast_id().erase(); @@ -2298,7 +2298,7 @@ impl ModCollector<'_, '_> { fn collect_macro_rules(&mut self, id: ItemTreeAstId, module: ModuleId) { let krate = self.def_collector.def_map.krate; let mac = &self.item_tree[id]; - let attrs = self.item_tree.attrs(self.def_collector.db, krate, AttrOwner::Item(id.erase())); + let attrs = self.item_tree.attrs(self.def_collector.db, krate, id.upcast()); let ast_id = InFile::new(self.file_id(), mac.ast_id.upcast()); let export_attr = || attrs.by_key(sym::macro_export); @@ -2387,7 +2387,7 @@ impl ModCollector<'_, '_> { // Case 1: builtin macros let mut helpers_opt = None; - let attrs = self.item_tree.attrs(self.def_collector.db, krate, AttrOwner::Item(id.erase())); + let attrs = self.item_tree.attrs(self.def_collector.db, krate, id.upcast()); let expander = if attrs.by_key(sym::rustc_builtin_macro).exists() { if let Some(expander) = find_builtin_macro(&mac.name) { match expander { From 4f5488590184e3fd176939515652646703e53dbf Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Thu, 12 Jun 2025 13:22:44 +0300 Subject: [PATCH 23/56] Fix comparison of proc macros Comparing the TypeId is not enough, they also contain data. --- .../hir-def/src/macro_expansion_tests/mod.rs | 6 ++- crates/hir-expand/src/proc_macro.rs | 4 +- crates/load-cargo/src/lib.rs | 6 ++- crates/test-fixture/src/lib.rs | 42 ++++++++++++++++++- 4 files changed, 52 insertions(+), 6 deletions(-) diff --git a/crates/hir-def/src/macro_expansion_tests/mod.rs b/crates/hir-def/src/macro_expansion_tests/mod.rs index dc4334ee08..b532156091 100644 --- a/crates/hir-def/src/macro_expansion_tests/mod.rs +++ b/crates/hir-def/src/macro_expansion_tests/mod.rs @@ -14,7 +14,7 @@ mod builtin_fn_macro; mod mbe; mod proc_macros; -use std::{iter, ops::Range, sync}; +use std::{any::TypeId, iter, ops::Range, sync}; use base_db::RootQueryDb; use expect_test::Expect; @@ -380,4 +380,8 @@ impl ProcMacroExpander for IdentityWhenValidProcMacroExpander { panic!("got invalid macro input: {:?}", parse.errors()); } } + + fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool { + other.type_id() == TypeId::of::() + } } diff --git a/crates/hir-expand/src/proc_macro.rs b/crates/hir-expand/src/proc_macro.rs index 1cd975b980..1c8ebb6f53 100644 --- a/crates/hir-expand/src/proc_macro.rs +++ b/crates/hir-expand/src/proc_macro.rs @@ -34,9 +34,7 @@ pub trait ProcMacroExpander: fmt::Debug + Send + Sync + RefUnwindSafe + Any { current_dir: String, ) -> Result; - fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool { - other.type_id() == self.type_id() - } + fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool; } impl PartialEq for dyn ProcMacroExpander { diff --git a/crates/load-cargo/src/lib.rs b/crates/load-cargo/src/lib.rs index 30e2d5416c..89b8631cd2 100644 --- a/crates/load-cargo/src/lib.rs +++ b/crates/load-cargo/src/lib.rs @@ -2,7 +2,7 @@ //! for incorporating changes. // Note, don't remove any public api from this. This API is consumed by external tools // to run rust-analyzer as a library. -use std::{collections::hash_map::Entry, mem, path::Path, sync}; +use std::{any::Any, collections::hash_map::Entry, mem, path::Path, sync}; use crossbeam_channel::{Receiver, unbounded}; use hir_expand::proc_macro::{ @@ -512,6 +512,10 @@ impl ProcMacroExpander for Expander { Err(err) => Err(ProcMacroExpansionError::System(err.to_string())), } } + + fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool { + (other as &dyn Any).downcast_ref::() == Some(self) + } } #[cfg(test)] diff --git a/crates/test-fixture/src/lib.rs b/crates/test-fixture/src/lib.rs index 8eb48f8d93..8937e53175 100644 --- a/crates/test-fixture/src/lib.rs +++ b/crates/test-fixture/src/lib.rs @@ -1,5 +1,5 @@ //! A set of high-level utility fixture methods to use in tests. -use std::{mem, str::FromStr, sync}; +use std::{any::TypeId, mem, str::FromStr, sync}; use base_db::{ Crate, CrateDisplayName, CrateGraphBuilder, CrateName, CrateOrigin, CrateWorkspaceData, @@ -677,6 +677,10 @@ impl ProcMacroExpander for IdentityProcMacroExpander { ) -> Result { Ok(subtree.clone()) } + + fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool { + other.type_id() == TypeId::of::() + } } // Expands to a macro_rules! macro, for issue #18089. @@ -708,6 +712,10 @@ impl ProcMacroExpander for Issue18089ProcMacroExpander { #subtree }) } + + fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool { + other.type_id() == TypeId::of::() + } } // Pastes the attribute input as its output @@ -728,6 +736,10 @@ impl ProcMacroExpander for AttributeInputReplaceProcMacroExpander { .cloned() .ok_or_else(|| ProcMacroExpansionError::Panic("Expected attribute input".into())) } + + fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool { + other.type_id() == TypeId::of::() + } } #[derive(Debug)] @@ -759,6 +771,10 @@ impl ProcMacroExpander for Issue18840ProcMacroExpander { top_subtree_delimiter_mut.close = def_site; Ok(result) } + + fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool { + other.type_id() == TypeId::of::() + } } #[derive(Debug)] @@ -790,6 +806,10 @@ impl ProcMacroExpander for MirrorProcMacroExpander { traverse(&mut builder, input.iter()); Ok(builder.build()) } + + fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool { + other.type_id() == TypeId::of::() + } } // Replaces every literal with an empty string literal and every identifier with its first letter, @@ -830,6 +850,10 @@ impl ProcMacroExpander for ShortenProcMacroExpander { } } } + + fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool { + other.type_id() == TypeId::of::() + } } // Reads ident type within string quotes, for issue #17479. @@ -855,6 +879,10 @@ impl ProcMacroExpander for Issue17479ProcMacroExpander { #symbol() }) } + + fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool { + other.type_id() == TypeId::of::() + } } // Reads ident type within string quotes, for issue #17479. @@ -906,6 +934,10 @@ impl ProcMacroExpander for Issue18898ProcMacroExpander { } }) } + + fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool { + other.type_id() == TypeId::of::() + } } // Reads ident type within string quotes, for issue #17479. @@ -933,6 +965,10 @@ impl ProcMacroExpander for DisallowCfgProcMacroExpander { } Ok(subtree.clone()) } + + fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool { + other.type_id() == TypeId::of::() + } } // Generates a new type by adding a suffix to the original name @@ -987,4 +1023,8 @@ impl ProcMacroExpander for GenerateSuffixedTypeProcMacroExpander { Ok(ret) } + + fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool { + other.type_id() == TypeId::of::() + } } From 23eef0c4eac5229d771fc676091e802ee05f9802 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 12 Jun 2025 11:51:33 +0200 Subject: [PATCH 24/56] Shrink `ModItem` by usize --- crates/hir-def/src/item_tree.rs | 30 ++++++++++++++++++------- crates/hir-def/src/item_tree/lower.rs | 25 +++++++++------------ crates/hir-def/src/nameres/collector.rs | 2 +- crates/intern/src/symbol.rs | 1 + 4 files changed, 34 insertions(+), 24 deletions(-) diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs index 79f4b174e1..2a277e4c54 100644 --- a/crates/hir-def/src/item_tree.rs +++ b/crates/hir-def/src/item_tree.rs @@ -51,7 +51,7 @@ use hir_expand::{ name::Name, }; use intern::Interned; -use la_arena::Idx; +use la_arena::{Idx, RawIdx}; use rustc_hash::FxHashMap; use span::{AstIdNode, Edition, FileAstId, SyntaxContext}; use stdx::never; @@ -437,10 +437,10 @@ pub struct Use { #[derive(Debug, Clone, Eq, PartialEq)] pub struct UseTree { - pub index: Idx, kind: UseTreeKind, } +// FIXME: Would be nice to encode `None` into this #[derive(Debug, Clone, PartialEq, Eq)] pub enum ImportAlias { /// Unnamed alias, as in `use Foo as _;` @@ -655,15 +655,17 @@ pub enum ImportKind { TypeOnly, } -impl UseTree { +impl Use { /// Expands the `UseTree` into individually imported `ModPath`s. pub fn expand( &self, mut cb: impl FnMut(Idx, ModPath, ImportKind, Option), ) { - self.expand_impl(None, &mut cb) + self.use_tree.expand_impl(None, &mut 0, &mut cb) } +} +impl UseTree { /// The [`UseTreeKind`] of this `UseTree`. pub fn kind(&self) -> &UseTreeKind { &self.kind @@ -672,6 +674,7 @@ impl UseTree { fn expand_impl( &self, prefix: Option, + counting_index: &mut u32, cb: &mut impl FnMut(Idx, ModPath, ImportKind, Option), ) { fn concat_mod_paths( @@ -707,17 +710,27 @@ impl UseTree { match &self.kind { UseTreeKind::Single { path, alias } => { if let Some((path, kind)) = concat_mod_paths(prefix, path) { - cb(self.index, path, kind, alias.clone()); + cb(Idx::from_raw(RawIdx::from_u32(*counting_index)), path, kind, alias.clone()); } } UseTreeKind::Glob { path: Some(path) } => { if let Some((path, _)) = concat_mod_paths(prefix, path) { - cb(self.index, path, ImportKind::Glob, None); + cb( + Idx::from_raw(RawIdx::from_u32(*counting_index)), + path, + ImportKind::Glob, + None, + ); } } UseTreeKind::Glob { path: None } => { if let Some(prefix) = prefix { - cb(self.index, prefix, ImportKind::Glob, None); + cb( + Idx::from_raw(RawIdx::from_u32(*counting_index)), + prefix, + ImportKind::Glob, + None, + ); } } UseTreeKind::Prefixed { prefix: additional_prefix, list } => { @@ -729,7 +742,8 @@ impl UseTree { None => prefix, }; for tree in &**list { - tree.expand_impl(prefix.clone(), cb); + *counting_index += 1; + tree.expand_impl(prefix.clone(), counting_index, cb); } } } diff --git a/crates/hir-def/src/item_tree/lower.rs b/crates/hir-def/src/item_tree/lower.rs index c3089eef90..ab60b7ad70 100644 --- a/crates/hir-def/src/item_tree/lower.rs +++ b/crates/hir-def/src/item_tree/lower.rs @@ -424,17 +424,15 @@ impl UseTreeLowering<'_> { } }; + self.mapping.alloc(tree.clone()); let list = use_tree_list .use_trees() .filter_map(|tree| self.lower_use_tree(tree, span_for_range)) .collect(); - Some( - self.use_tree( - UseTreeKind::Prefixed { prefix: prefix.map(Interned::new), list }, - tree, - ), - ) + Some(UseTree { + kind: UseTreeKind::Prefixed { prefix: prefix.map(Interned::new), list }, + }) } else { let is_glob = tree.star_token().is_some(); let path = match tree.path() { @@ -453,23 +451,20 @@ impl UseTreeLowering<'_> { if path.is_none() { cov_mark::hit!(glob_enum_group); } - Some(self.use_tree(UseTreeKind::Glob { path: path.map(Interned::new) }, tree)) + self.mapping.alloc(tree.clone()); + Some(UseTree { kind: UseTreeKind::Glob { path: path.map(Interned::new) } }) } // Globs can't be renamed (_, Some(_), true) | (None, None, false) => None, // `bla::{ as Name}` is invalid (None, Some(_), false) => None, - (Some(path), alias, false) => Some( - self.use_tree(UseTreeKind::Single { path: Interned::new(path), alias }, tree), - ), + (Some(path), alias, false) => { + self.mapping.alloc(tree.clone()); + Some(UseTree { kind: UseTreeKind::Single { path: Interned::new(path), alias } }) + } } } } - - fn use_tree(&mut self, kind: UseTreeKind, ast: ast::UseTree) -> UseTree { - let index = self.mapping.alloc(ast); - UseTree { index, kind } - } } pub(crate) fn lower_use_tree( diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index a6be3f1fbf..9801875ee4 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -163,7 +163,7 @@ impl Import { ) { let it = &tree[item]; let visibility = &tree[it.visibility]; - it.use_tree.expand(|idx, path, kind, alias| { + it.expand(|idx, path, kind, alias| { cb(Self { path, alias, diff --git a/crates/intern/src/symbol.rs b/crates/intern/src/symbol.rs index 8b2d6e8717..3b962a86f1 100644 --- a/crates/intern/src/symbol.rs +++ b/crates/intern/src/symbol.rs @@ -112,6 +112,7 @@ impl TaggedArcPtr { } } +// FIXME: This should have more than one niche #[derive(PartialEq, Eq, Hash)] pub struct Symbol { repr: TaggedArcPtr, From 2448abdb558a88b86234d746470bac9d67f2fde2 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 12 Jun 2025 12:02:53 +0200 Subject: [PATCH 25/56] Remove dead code --- crates/hir-def/src/item_tree.rs | 70 ++++++++++--------------- crates/hir-def/src/nameres/collector.rs | 16 +++--- 2 files changed, 35 insertions(+), 51 deletions(-) diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs index 2a277e4c54..0836d5758b 100644 --- a/crates/hir-def/src/item_tree.rs +++ b/crates/hir-def/src/item_tree.rs @@ -63,13 +63,13 @@ 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); +pub(crate) struct RawVisibilityId(u32); impl RawVisibilityId { - pub const PUB: Self = RawVisibilityId(u32::MAX); - pub const PRIV_IMPLICIT: Self = RawVisibilityId(u32::MAX - 1); - pub const PRIV_EXPLICIT: Self = RawVisibilityId(u32::MAX - 2); - pub const PUB_CRATE: Self = RawVisibilityId(u32::MAX - 3); + const PUB: Self = RawVisibilityId(u32::MAX); + const PRIV_IMPLICIT: Self = RawVisibilityId(u32::MAX - 1); + const PRIV_EXPLICIT: Self = RawVisibilityId(u32::MAX - 2); + const PUB_CRATE: Self = RawVisibilityId(u32::MAX - 3); } impl fmt::Debug for RawVisibilityId { @@ -188,12 +188,12 @@ impl ItemTree { } /// Returns the inner attributes of the source file. - pub fn top_level_raw_attrs(&self) -> &RawAttrs { + pub(crate) fn top_level_raw_attrs(&self) -> &RawAttrs { &self.top_attrs } /// Returns the inner attributes of the source file. - pub fn top_level_attrs(&self, db: &dyn DefDatabase, krate: Crate) -> Attrs { + pub(crate) fn top_level_attrs(&self, db: &dyn DefDatabase, krate: Crate) -> Attrs { Attrs::expand_cfg_attr(db, krate, self.top_attrs.clone()) } @@ -278,17 +278,12 @@ pub struct ItemTreeDataStats { } /// Trait implemented by all nodes in the item tree. -pub trait ItemTreeNode: Clone { +pub(crate) trait ItemTreeNode: Clone { type Source: AstIdNode; - - fn ast_id(&self) -> FileAstId; - - /// Looks up an instance of `Self` in an item tree. - fn lookup(tree: &ItemTree, index: FileAstId) -> &Self; } #[allow(type_alias_bounds)] -pub type ItemTreeAstId = FileAstId; +pub(crate) type ItemTreeAstId = FileAstId; /// Identifies a particular [`ItemTree`]. #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] @@ -298,11 +293,11 @@ pub struct TreeId { } impl TreeId { - pub fn new(file: HirFileId, block: Option) -> Self { + pub(crate) fn new(file: HirFileId, block: Option) -> Self { Self { file, block } } - pub fn item_tree(&self, db: &dyn DefDatabase) -> Arc { + pub(crate) fn item_tree(&self, db: &dyn DefDatabase) -> Arc { match self.block { Some(block) => db.block_item_tree(block), None => db.file_item_tree(self.file), @@ -314,7 +309,7 @@ impl TreeId { self.file } - pub fn is_block(self) -> bool { + pub(crate) fn is_block(self) -> bool { self.block.is_some() } } @@ -347,17 +342,6 @@ macro_rules! mod_items { $( impl ItemTreeNode for $typ { type Source = $ast; - - fn ast_id(&self) -> FileAstId<$ast> { - self.ast_id - } - - fn lookup(tree: &ItemTree, index: FileAstId<$ast>) -> &Self { - match &tree.data[&index.upcast()] { - ModItem::$typ(item) => item, - _ => panic!("expected item of type `{}` at index `{:?}`", stringify!($typ), index), - } - } } impl Index> for ItemTree { @@ -430,9 +414,9 @@ impl Index for ItemTree { #[derive(Debug, Clone, Eq, PartialEq)] pub struct Use { - pub visibility: RawVisibilityId, - pub ast_id: FileAstId, - pub use_tree: UseTree, + pub(crate) visibility: RawVisibilityId, + pub(crate) ast_id: FileAstId, + pub(crate) use_tree: UseTree, } #[derive(Debug, Clone, Eq, PartialEq)] @@ -494,7 +478,7 @@ pub enum UseTreeKind { pub struct ExternCrate { pub name: Name, pub alias: Option, - pub visibility: RawVisibilityId, + pub(crate) visibility: RawVisibilityId, pub ast_id: FileAstId, } @@ -507,14 +491,14 @@ pub struct ExternBlock { #[derive(Debug, Clone, Eq, PartialEq)] pub struct Function { pub name: Name, - pub visibility: RawVisibilityId, + pub(crate) visibility: RawVisibilityId, pub ast_id: FileAstId, } #[derive(Debug, Clone, Eq, PartialEq)] pub struct Struct { pub name: Name, - pub visibility: RawVisibilityId, + pub(crate) visibility: RawVisibilityId, pub shape: FieldsShape, pub ast_id: FileAstId, } @@ -522,14 +506,14 @@ pub struct Struct { #[derive(Debug, Clone, Eq, PartialEq)] pub struct Union { pub name: Name, - pub visibility: RawVisibilityId, + pub(crate) visibility: RawVisibilityId, pub ast_id: FileAstId, } #[derive(Debug, Clone, Eq, PartialEq)] pub struct Enum { pub name: Name, - pub visibility: RawVisibilityId, + pub(crate) visibility: RawVisibilityId, pub ast_id: FileAstId, } @@ -568,28 +552,28 @@ impl VisibilityExplicitness { pub struct Const { /// `None` for `const _: () = ();` pub name: Option, - pub visibility: RawVisibilityId, + pub(crate) visibility: RawVisibilityId, pub ast_id: FileAstId, } #[derive(Debug, Clone, Eq, PartialEq)] pub struct Static { pub name: Name, - pub visibility: RawVisibilityId, + pub(crate) visibility: RawVisibilityId, pub ast_id: FileAstId, } #[derive(Debug, Clone, Eq, PartialEq)] pub struct Trait { pub name: Name, - pub visibility: RawVisibilityId, + pub(crate) visibility: RawVisibilityId, pub ast_id: FileAstId, } #[derive(Debug, Clone, Eq, PartialEq)] pub struct TraitAlias { pub name: Name, - pub visibility: RawVisibilityId, + pub(crate) visibility: RawVisibilityId, pub ast_id: FileAstId, } @@ -601,14 +585,14 @@ pub struct Impl { #[derive(Debug, Clone, PartialEq, Eq)] pub struct TypeAlias { pub name: Name, - pub visibility: RawVisibilityId, + pub(crate) visibility: RawVisibilityId, pub ast_id: FileAstId, } #[derive(Debug, Clone, Eq, PartialEq)] pub struct Mod { pub name: Name, - pub visibility: RawVisibilityId, + pub(crate) visibility: RawVisibilityId, pub(crate) kind: ModKind, pub ast_id: FileAstId, } @@ -641,7 +625,7 @@ pub struct MacroRules { #[derive(Debug, Clone, Eq, PartialEq)] pub struct Macro2 { pub name: Name, - pub visibility: RawVisibilityId, + pub(crate) visibility: RawVisibilityId, pub ast_id: FileAstId, } diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index 9801875ee4..4d19df0195 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -35,8 +35,8 @@ use crate::{ db::DefDatabase, item_scope::{GlobId, ImportId, ImportOrExternCrate, PerNsGlobImports}, item_tree::{ - self, FieldsShape, ImportAlias, ImportKind, ItemTree, ItemTreeAstId, ItemTreeNode, Macro2, - MacroCall, MacroRules, Mod, ModItemId, ModKind, TreeId, UseTreeKind, + self, FieldsShape, ImportAlias, ImportKind, ItemTree, ItemTreeAstId, Macro2, MacroCall, + MacroRules, Mod, ModItemId, ModKind, TreeId, UseTreeKind, }, macro_call_as_call_id, nameres::{ @@ -1436,9 +1436,9 @@ impl DefCollector<'_> { let item_tree = tree.item_tree(self.db); let ast_adt_id: FileAstId = match *mod_item { - ModItemId::Struct(strukt) => item_tree[strukt].ast_id().upcast(), - ModItemId::Union(union) => item_tree[union].ast_id().upcast(), - ModItemId::Enum(enum_) => item_tree[enum_].ast_id().upcast(), + ModItemId::Struct(strukt) => item_tree[strukt].ast_id.upcast(), + ModItemId::Union(union) => item_tree[union].ast_id.upcast(), + ModItemId::Enum(enum_) => item_tree[enum_].ast_id.upcast(), _ => { let diag = DefDiagnostic::invalid_derive_target( directive.module_id, @@ -1889,7 +1889,7 @@ impl ModCollector<'_, '_> { if let Some(proc_macro) = attrs.parse_proc_macro_decl(&it.name) { self.def_collector.export_proc_macro( proc_macro, - InFile::new(self.file_id(), self.item_tree[id].ast_id()), + InFile::new(self.file_id(), self.item_tree[id].ast_id), fn_id, ); } @@ -2369,7 +2369,7 @@ impl ModCollector<'_, '_> { } .intern(self.def_collector.db); self.def_collector.def_map.macro_def_to_macro_id.insert( - InFile::new(self.file_id(), self.item_tree[id].ast_id()).erase(), + InFile::new(self.file_id(), self.item_tree[id].ast_id).erase(), macro_id.into(), ); self.def_collector.define_macro_rules( @@ -2437,7 +2437,7 @@ impl ModCollector<'_, '_> { } .intern(self.def_collector.db); self.def_collector.def_map.macro_def_to_macro_id.insert( - InFile::new(self.file_id(), self.item_tree[id].ast_id()).erase(), + InFile::new(self.file_id(), self.item_tree[id].ast_id).erase(), macro_id.into(), ); self.def_collector.define_macro_def( From d8a6aaef966b3eaa1f4cc9f6f0e59f0842bf25da Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 12 Jun 2025 12:50:04 +0200 Subject: [PATCH 26/56] Return item tree query results by ref --- crates/hir-def/src/attr.rs | 3 +- crates/hir-def/src/db.rs | 10 +- crates/hir-def/src/item_tree.rs | 158 +++++++++++------------- crates/hir-def/src/nameres/collector.rs | 10 +- 4 files changed, 82 insertions(+), 99 deletions(-) diff --git a/crates/hir-def/src/attr.rs b/crates/hir-def/src/attr.rs index d63bd391fd..b509e69b0d 100644 --- a/crates/hir-def/src/attr.rs +++ b/crates/hir-def/src/attr.rs @@ -26,6 +26,7 @@ use crate::{ AdtId, AstIdLoc, AttrDefId, GenericParamId, HasModule, LocalFieldId, Lookup, MacroId, VariantId, db::DefDatabase, + item_tree::block_item_tree_query, lang_item::LangItem, nameres::{ModuleOrigin, ModuleSource}, src::{HasChildSource, HasSource}, @@ -539,7 +540,7 @@ impl AttrsWithOwner { definition_tree_id.item_tree(db).raw_attrs(definition.upcast()).clone() } ModuleOrigin::BlockExpr { id, .. } => { - let tree = db.block_item_tree(id); + let tree = block_item_tree_query(db, id); tree.top_level_raw_attrs().clone() } }; diff --git a/crates/hir-def/src/db.rs b/crates/hir-def/src/db.rs index 5f99693139..27fe62c4f0 100644 --- a/crates/hir-def/src/db.rs +++ b/crates/hir-def/src/db.rs @@ -24,7 +24,7 @@ use crate::{ }, hir::generics::GenericParams, import_map::ImportMap, - item_tree::ItemTree, + item_tree::{ItemTree, file_item_tree_query}, lang_item::{self, LangItem}, nameres::{ assoc::{ImplItems, TraitItems}, @@ -108,11 +108,9 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + SourceDatabase { fn expand_proc_attr_macros(&self) -> bool; /// Computes an [`ItemTree`] for the given file or macro expansion. - #[salsa::invoke(ItemTree::file_item_tree_query)] - fn file_item_tree(&self, file_id: HirFileId) -> Arc; - - #[salsa::invoke(ItemTree::block_item_tree_query)] - fn block_item_tree(&self, block_id: BlockId) -> Arc; + #[salsa::invoke(file_item_tree_query)] + #[salsa::transparent] + fn file_item_tree(&self, file_id: HirFileId) -> &ItemTree; /// Turns a MacroId into a MacroDefId, describing the macro's definition post name resolution. #[salsa::invoke(macro_def)] diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs index 0836d5758b..90a5dd2dc7 100644 --- a/crates/hir-def/src/item_tree.rs +++ b/crates/hir-def/src/item_tree.rs @@ -85,6 +85,74 @@ impl fmt::Debug for RawVisibilityId { } } +#[salsa_macros::tracked(returns(ref))] +pub(crate) fn file_item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> ItemTree { + let _p = tracing::info_span!("file_item_tree_query", ?file_id).entered(); + + let ctx = lower::Ctx::new(db, file_id); + let syntax = db.parse_or_expand(file_id); + let mut item_tree = match_ast! { + match syntax { + ast::SourceFile(file) => { + let top_attrs = RawAttrs::new(db, &file, ctx.span_map()); + let mut item_tree = ctx.lower_module_items(&file); + item_tree.top_attrs = top_attrs; + item_tree + }, + ast::MacroItems(items) => { + ctx.lower_module_items(&items) + }, + ast::MacroStmts(stmts) => { + // The produced statements can include items, which should be added as top-level + // items. + ctx.lower_macro_stmts(stmts) + }, + _ => { + if never!(syntax.kind() == SyntaxKind::ERROR, "{:?} from {:?} {}", file_id, syntax, syntax) { + return Default::default(); + } + panic!("cannot create item tree for file {file_id:?} from {syntax:?} {syntax}"); + }, + } + }; + + item_tree.shrink_to_fit(); + item_tree +} + +#[salsa_macros::tracked(returns(ref))] +pub(crate) fn block_item_tree_query(db: &dyn DefDatabase, block: BlockId) -> Arc { + let _p = tracing::info_span!("block_item_tree_query", ?block).entered(); + // Blocks have a tendency to be empty due to macro calls that do not expand to items, + // so deduplicate this case via `Arc` to reduce the size of the query storage here. + static EMPTY: OnceLock> = OnceLock::new(); + + let loc = block.lookup(db); + let block = loc.ast_id.to_node(db); + + let ctx = lower::Ctx::new(db, loc.ast_id.file_id); + let mut item_tree = ctx.lower_block(&block); + if item_tree.data.is_empty() + && item_tree.top_level.is_empty() + && item_tree.attrs.is_empty() + && item_tree.top_attrs.is_empty() + { + EMPTY + .get_or_init(|| { + Arc::new(ItemTree { + top_level: Box::new([]), + attrs: FxHashMap::default(), + data: FxHashMap::default(), + top_attrs: RawAttrs::EMPTY, + vis: ItemVisibilities { arena: Box::new([]) }, + }) + }) + .clone() + } else { + item_tree.shrink_to_fit(); + Arc::new(item_tree) + } +} /// The item tree of a source file. #[derive(Debug, Default, Eq, PartialEq)] pub struct ItemTree { @@ -97,90 +165,6 @@ pub struct ItemTree { } impl ItemTree { - pub(crate) fn file_item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc { - let _p = tracing::info_span!("file_item_tree_query", ?file_id).entered(); - static EMPTY: OnceLock> = OnceLock::new(); - - let ctx = lower::Ctx::new(db, file_id); - let syntax = db.parse_or_expand(file_id); - let mut item_tree = match_ast! { - match syntax { - ast::SourceFile(file) => { - let top_attrs = RawAttrs::new(db, &file, ctx.span_map()); - let mut item_tree = ctx.lower_module_items(&file); - item_tree.top_attrs = top_attrs; - item_tree - }, - ast::MacroItems(items) => { - ctx.lower_module_items(&items) - }, - ast::MacroStmts(stmts) => { - // The produced statements can include items, which should be added as top-level - // items. - ctx.lower_macro_stmts(stmts) - }, - _ => { - if never!(syntax.kind() == SyntaxKind::ERROR, "{:?} from {:?} {}", file_id, syntax, syntax) { - return Default::default(); - } - panic!("cannot create item tree for file {file_id:?} from {syntax:?} {syntax}"); - }, - } - }; - - if item_tree.data.is_empty() - && item_tree.top_level.is_empty() - && item_tree.attrs.is_empty() - && item_tree.top_attrs.is_empty() - { - EMPTY - .get_or_init(|| { - Arc::new(ItemTree { - top_level: Box::new([]), - attrs: FxHashMap::default(), - data: FxHashMap::default(), - top_attrs: RawAttrs::EMPTY, - vis: ItemVisibilities { arena: Box::new([]) }, - }) - }) - .clone() - } else { - item_tree.shrink_to_fit(); - Arc::new(item_tree) - } - } - - pub(crate) fn block_item_tree_query(db: &dyn DefDatabase, block: BlockId) -> Arc { - let _p = tracing::info_span!("block_item_tree_query", ?block).entered(); - static EMPTY: OnceLock> = OnceLock::new(); - - let loc = block.lookup(db); - let block = loc.ast_id.to_node(db); - - let ctx = lower::Ctx::new(db, loc.ast_id.file_id); - let mut item_tree = ctx.lower_block(&block); - if item_tree.data.is_empty() - && item_tree.top_level.is_empty() - && item_tree.attrs.is_empty() - && item_tree.top_attrs.is_empty() - { - EMPTY - .get_or_init(|| { - Arc::new(ItemTree { - top_level: Box::new([]), - attrs: FxHashMap::default(), - data: FxHashMap::default(), - top_attrs: RawAttrs::EMPTY, - vis: ItemVisibilities { arena: Box::new([]) }, - }) - }) - .clone() - } else { - item_tree.shrink_to_fit(); - Arc::new(item_tree) - } - } - /// Returns an iterator over all items located at the top level of the `HirFileId` this /// `ItemTree` was created from. pub(crate) fn top_level_items(&self) -> &[ModItemId] { @@ -297,10 +281,10 @@ impl TreeId { Self { file, block } } - pub(crate) fn item_tree(&self, db: &dyn DefDatabase) -> Arc { + pub(crate) fn item_tree<'db>(&self, db: &'db dyn DefDatabase) -> &'db ItemTree { match self.block { - Some(block) => db.block_item_tree(block), - None => db.file_item_tree(self.file), + Some(block) => block_item_tree_query(db, block), + None => file_item_tree_query(db, self.file), } } diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index 4d19df0195..3b2488c8ea 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -357,7 +357,7 @@ impl DefCollector<'_> { macro_depth: 0, module_id: DefMap::ROOT, tree_id: TreeId::new(file_id.into(), None), - item_tree: &item_tree, + item_tree, mod_dir: ModDir::root(), } .collect_in_top_module(item_tree.top_level_items()); @@ -378,7 +378,7 @@ impl DefCollector<'_> { macro_depth: 0, module_id: DefMap::ROOT, tree_id, - item_tree: &item_tree, + item_tree, mod_dir: ModDir::root(), } .collect_in_top_module(item_tree.top_level_items()); @@ -1381,7 +1381,7 @@ impl DefCollector<'_> { macro_depth: directive.depth, module_id: directive.module_id, tree_id: *tree, - item_tree: &item_tree, + item_tree, mod_dir, } .collect(&[*mod_item], directive.container); @@ -1570,7 +1570,7 @@ impl DefCollector<'_> { macro_depth: depth, tree_id: TreeId::new(file_id, None), module_id, - item_tree: &item_tree, + item_tree, mod_dir, } .collect(item_tree.top_level_items(), container); @@ -2142,7 +2142,7 @@ impl ModCollector<'_, '_> { macro_depth: self.macro_depth, module_id, tree_id: TreeId::new(file_id.into(), None), - item_tree: &item_tree, + item_tree, mod_dir, } .collect_in_top_module(item_tree.top_level_items()); From 17d848a1bba641a3722d87e4c19e24afc4fd32ce Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 12 Jun 2025 14:01:46 +0200 Subject: [PATCH 27/56] Fix tests --- crates/hir-def/src/nameres/tests/incremental.rs | 12 ++++++------ crates/hir-ty/src/tests/incremental.rs | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/crates/hir-def/src/nameres/tests/incremental.rs b/crates/hir-def/src/nameres/tests/incremental.rs index 948e8bed66..7a4ea62f12 100644 --- a/crates/hir-def/src/nameres/tests/incremental.rs +++ b/crates/hir-def/src/nameres/tests/incremental.rs @@ -348,7 +348,7 @@ m!(Z); assert_eq!(module_data.scope.resolutions().count(), 4); }); let n_recalculated_item_trees = - events.iter().filter(|it| it.contains("file_item_tree_shim")).count(); + events.iter().filter(|it| it.contains("file_item_tree_query")).count(); assert_eq!(n_recalculated_item_trees, 6); let n_reparsed_macros = events.iter().filter(|it| it.contains("parse_macro_expansion_shim")).count(); @@ -370,7 +370,7 @@ m!(Z); assert_eq!(module_data.scope.resolutions().count(), 4); }); let n_recalculated_item_trees = - events.iter().filter(|it| it.contains("file_item_tree_shim")).count(); + events.iter().filter(|it| it.contains("file_item_tree_query")).count(); assert_eq!(n_recalculated_item_trees, 1, "{events:#?}"); let n_reparsed_macros = events.iter().filter(|it| it.contains("parse_macro_expansion_shim")).count(); @@ -405,10 +405,10 @@ pub type Ty = (); db.file_item_tree(pos.file_id.into()); }); let n_calculated_item_trees = - events.iter().filter(|it| it.contains("file_item_tree_shim")).count(); - assert_eq!(n_calculated_item_trees, 1); + events.iter().filter(|it| it.contains("file_item_tree_query")).count(); + assert_eq!(n_calculated_item_trees, 1, "{events:#?}"); let n_parsed_files = events.iter().filter(|it| it.contains("parse")).count(); - assert_eq!(n_parsed_files, 1); + assert_eq!(n_parsed_files, 1, "{events:#?}"); } // FIXME(salsa-transition): bring this back @@ -446,6 +446,6 @@ pub type Ty = (); } }); let n_reparsed_files = events.iter().filter(|it| it.contains("parse(")).count(); - assert_eq!(n_reparsed_files, 0); + assert_eq!(n_reparsed_files, 0, "{events:?}"); } } diff --git a/crates/hir-ty/src/tests/incremental.rs b/crates/hir-ty/src/tests/incremental.rs index a055ef879d..74f6bbb030 100644 --- a/crates/hir-ty/src/tests/incremental.rs +++ b/crates/hir-ty/src/tests/incremental.rs @@ -156,7 +156,7 @@ pub struct NewStruct { let expected = vec![ "parse_shim".to_owned(), "ast_id_map_shim".to_owned(), - "file_item_tree_shim".to_owned(), + "file_item_tree_query".to_owned(), "real_span_map_shim".to_owned(), "crate_local_def_map".to_owned(), "trait_impls_in_crate_shim".to_owned(), @@ -216,7 +216,7 @@ pub enum SomeEnum { let expected = vec![ "parse_shim".to_owned(), "ast_id_map_shim".to_owned(), - "file_item_tree_shim".to_owned(), + "file_item_tree_query".to_owned(), "real_span_map_shim".to_owned(), "crate_local_def_map".to_owned(), "trait_impls_in_crate_shim".to_owned(), @@ -273,7 +273,7 @@ fn bar() -> f32 { let expected = vec![ "parse_shim".to_owned(), "ast_id_map_shim".to_owned(), - "file_item_tree_shim".to_owned(), + "file_item_tree_query".to_owned(), "real_span_map_shim".to_owned(), "crate_local_def_map".to_owned(), "trait_impls_in_crate_shim".to_owned(), @@ -342,7 +342,7 @@ impl SomeStruct { let expected = vec![ "parse_shim".to_owned(), "ast_id_map_shim".to_owned(), - "file_item_tree_shim".to_owned(), + "file_item_tree_query".to_owned(), "real_span_map_shim".to_owned(), "crate_local_def_map".to_owned(), "trait_impls_in_crate_shim".to_owned(), From 3e834add61baf2f67fe27ac3b13b81bf914c6a60 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Thu, 12 Jun 2025 15:32:08 +0300 Subject: [PATCH 28/56] Support spans with proc macro servers from before the ast id changes The only thing changed is the value of the fixup ast id, so we just swap it. --- .../proc-macro-api/src/legacy_protocol/msg.rs | 4 +- crates/proc-macro-api/src/lib.rs | 70 ++++++++++++++++--- crates/proc-macro-api/src/process.rs | 14 ++-- crates/proc-macro-srv-cli/src/main_loop.rs | 7 +- crates/proc-macro-srv/src/dylib.rs | 15 ++-- crates/proc-macro-srv/src/lib.rs | 32 ++------- crates/proc-macro-srv/src/proc_macros.rs | 8 +-- .../src/server_impl/rust_analyzer_span.rs | 13 ++-- crates/proc-macro-srv/src/tests/utils.rs | 28 ++------ crates/span/src/ast_id.rs | 7 +- 10 files changed, 96 insertions(+), 102 deletions(-) diff --git a/crates/proc-macro-api/src/legacy_protocol/msg.rs b/crates/proc-macro-api/src/legacy_protocol/msg.rs index 4e1526fe48..165936269d 100644 --- a/crates/proc-macro-api/src/legacy_protocol/msg.rs +++ b/crates/proc-macro-api/src/legacy_protocol/msg.rs @@ -55,7 +55,7 @@ pub enum SpanMode { Id, /// Rust Analyzer-specific span handling mode. - RustAnalyzer { fixup_ast_id: u32 }, + RustAnalyzer, } /// Represents responses sent from the proc-macro-srv to the client. @@ -308,7 +308,7 @@ mod tests { #[test] fn test_proc_macro_rpc_works() { let tt = fixture_token_tree(); - for v in HASHED_AST_ID..=CURRENT_API_VERSION { + for v in RUST_ANALYZER_SPAN_SUPPORT..=CURRENT_API_VERSION { let mut span_data_table = Default::default(); let task = ExpandMacro { data: ExpandMacroData { diff --git a/crates/proc-macro-api/src/lib.rs b/crates/proc-macro-api/src/lib.rs index 25c30b6db4..516c7418bd 100644 --- a/crates/proc-macro-api/src/lib.rs +++ b/crates/proc-macro-api/src/lib.rs @@ -12,13 +12,13 @@ pub mod legacy_protocol { mod process; use paths::{AbsPath, AbsPathBuf}; -use span::Span; +use span::{ErasedFileAstId, FIXUP_ERASED_FILE_AST_ID_MARKER, Span}; use std::{fmt, io, sync::Arc, time::SystemTime}; use crate::{ legacy_protocol::msg::{ - ExpandMacro, ExpandMacroData, ExpnGlobals, FlatTree, HAS_GLOBAL_SPANS, PanicMessage, - RUST_ANALYZER_SPAN_SUPPORT, Request, Response, SpanDataIndexMap, + ExpandMacro, ExpandMacroData, ExpnGlobals, FlatTree, HAS_GLOBAL_SPANS, HASHED_AST_ID, + PanicMessage, RUST_ANALYZER_SPAN_SUPPORT, Request, Response, SpanDataIndexMap, deserialize_span_data_index_map, flat::serialize_span_data_index_map, }, process::ProcMacroServerProcess, @@ -161,6 +161,38 @@ impl ProcMacro { self.kind } + fn needs_fixup_change(&self) -> bool { + let version = self.process.version(); + (RUST_ANALYZER_SPAN_SUPPORT..HASHED_AST_ID).contains(&version) + } + + /// On some server versions, the fixup ast id is different than ours. So change it to match. + fn change_fixup_to_match_old_server(&self, tt: &mut tt::TopSubtree) { + const OLD_FIXUP_AST_ID: ErasedFileAstId = ErasedFileAstId::from_raw(!0 - 1); + let change_ast_id = |ast_id: &mut ErasedFileAstId| { + if *ast_id == FIXUP_ERASED_FILE_AST_ID_MARKER { + *ast_id = OLD_FIXUP_AST_ID; + } else if *ast_id == OLD_FIXUP_AST_ID { + // Swap between them, that means no collision plus the change can be reversed by doing itself. + *ast_id = FIXUP_ERASED_FILE_AST_ID_MARKER; + } + }; + + for tt in &mut tt.0 { + match tt { + tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { span, .. })) + | tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal { span, .. })) + | tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { span, .. })) => { + change_ast_id(&mut span.anchor.ast_id); + } + tt::TokenTree::Subtree(subtree) => { + change_ast_id(&mut subtree.delimiter.open.anchor.ast_id); + change_ast_id(&mut subtree.delimiter.close.anchor.ast_id); + } + } + } + } + /// Expands the procedural macro by sending an expansion request to the server. /// This includes span information and environmental context. pub fn expand( @@ -173,6 +205,20 @@ impl ProcMacro { mixed_site: Span, current_dir: String, ) -> Result, PanicMessage>, ServerError> { + let (mut subtree, mut attr) = (subtree, attr); + let (mut subtree_changed, mut attr_changed); + if self.needs_fixup_change() { + subtree_changed = tt::TopSubtree::from_subtree(subtree); + self.change_fixup_to_match_old_server(&mut subtree_changed); + subtree = subtree_changed.view(); + + if let Some(attr) = &mut attr { + attr_changed = tt::TopSubtree::from_subtree(*attr); + self.change_fixup_to_match_old_server(&mut attr_changed); + *attr = attr_changed.view(); + } + } + let version = self.process.version(); let mut span_data_table = SpanDataIndexMap::default(); @@ -205,15 +251,23 @@ impl ProcMacro { let response = self.process.send_task(Request::ExpandMacro(Box::new(task)))?; match response { - Response::ExpandMacro(it) => { - Ok(it.map(|tree| FlatTree::to_subtree_resolved(tree, version, &span_data_table))) - } + Response::ExpandMacro(it) => Ok(it.map(|tree| { + let mut expanded = FlatTree::to_subtree_resolved(tree, version, &span_data_table); + if self.needs_fixup_change() { + self.change_fixup_to_match_old_server(&mut expanded); + } + expanded + })), Response::ExpandMacroExtended(it) => Ok(it.map(|resp| { - FlatTree::to_subtree_resolved( + let mut expanded = FlatTree::to_subtree_resolved( resp.tree, version, &deserialize_span_data_index_map(&resp.span_data_table), - ) + ); + if self.needs_fixup_change() { + self.change_fixup_to_match_old_server(&mut expanded); + } + expanded })), _ => Err(ServerError { message: "unexpected response".to_owned(), io: None }), } diff --git a/crates/proc-macro-api/src/process.rs b/crates/proc-macro-api/src/process.rs index e3b0614546..fcea75ef67 100644 --- a/crates/proc-macro-api/src/process.rs +++ b/crates/proc-macro-api/src/process.rs @@ -8,7 +8,6 @@ use std::{ }; use paths::AbsPath; -use span::FIXUP_ERASED_FILE_AST_ID_MARKER; use stdx::JodChild; use crate::{ @@ -16,7 +15,8 @@ use crate::{ legacy_protocol::{ json::{read_json, write_json}, msg::{ - CURRENT_API_VERSION, HASHED_AST_ID, Message, Request, Response, ServerConfig, SpanMode, + CURRENT_API_VERSION, Message, RUST_ANALYZER_SPAN_SUPPORT, Request, Response, + ServerConfig, SpanMode, }, }, }; @@ -71,9 +71,7 @@ impl ProcMacroServerProcess { Ok(v) => { tracing::info!("Proc-macro server version: {v}"); srv.version = v; - 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 srv.version >= RUST_ANALYZER_SPAN_SUPPORT { if let Ok(mode) = srv.enable_rust_analyzer_spans() { srv.mode = mode; } @@ -113,11 +111,7 @@ impl ProcMacroServerProcess { /// Enable support for rust-analyzer span mode if the server supports it. fn enable_rust_analyzer_spans(&self) -> Result { - let request = Request::SetConfig(ServerConfig { - span_mode: SpanMode::RustAnalyzer { - fixup_ast_id: FIXUP_ERASED_FILE_AST_ID_MARKER.into_raw(), - }, - }); + let request = Request::SetConfig(ServerConfig { span_mode: SpanMode::RustAnalyzer }); let response = self.send_task(request)?; match response { diff --git a/crates/proc-macro-srv-cli/src/main_loop.rs b/crates/proc-macro-srv-cli/src/main_loop.rs index 25a49fbff9..f54dff1f2d 100644 --- a/crates/proc-macro-srv-cli/src/main_loop.rs +++ b/crates/proc-macro-srv-cli/src/main_loop.rs @@ -26,7 +26,7 @@ pub(crate) fn run() -> io::Result<()> { let write_response = |msg: msg::Response| msg.write(write_json, &mut io::stdout().lock()); let env = EnvSnapshot::default(); - let mut srv = proc_macro_srv::ProcMacroSrv::new(&env); + let srv = proc_macro_srv::ProcMacroSrv::new(&env); let mut span_mode = SpanMode::Id; @@ -78,7 +78,7 @@ pub(crate) fn run() -> io::Result<()> { }) .map_err(msg::PanicMessage) }), - SpanMode::RustAnalyzer { .. } => msg::Response::ExpandMacroExtended({ + SpanMode::RustAnalyzer => msg::Response::ExpandMacroExtended({ let mut span_data_table = deserialize_span_data_index_map(&span_data_table); let def_site = span_data_table[def_site]; @@ -122,9 +122,6 @@ pub(crate) fn run() -> io::Result<()> { msg::Request::ApiVersionCheck {} => msg::Response::ApiVersionCheck(CURRENT_API_VERSION), msg::Request::SetConfig(config) => { span_mode = config.span_mode; - if let SpanMode::RustAnalyzer { fixup_ast_id } = span_mode { - srv.set_fixup_ast_id(fixup_ast_id); - } msg::Response::SetConfig(config) } }; diff --git a/crates/proc-macro-srv/src/dylib.rs b/crates/proc-macro-srv/src/dylib.rs index c64a9833e3..c49159df99 100644 --- a/crates/proc-macro-srv/src/dylib.rs +++ b/crates/proc-macro-srv/src/dylib.rs @@ -3,7 +3,6 @@ mod version; use proc_macro::bridge; -use span::ErasedFileAstId; use std::{fmt, fs, io, time::SystemTime}; use libloading::Library; @@ -162,20 +161,14 @@ impl Expander { def_site: S, call_site: S, mixed_site: S, - fixup_ast_id: ErasedFileAstId, ) -> Result, String> where ::TokenStream: Default, { - let result = self.inner.proc_macros.expand( - macro_name, - macro_body, - attributes, - def_site, - call_site, - mixed_site, - fixup_ast_id, - ); + let result = self + .inner + .proc_macros + .expand(macro_name, macro_body, attributes, def_site, call_site, mixed_site); result.map_err(|e| e.into_string().unwrap_or_default()) } diff --git a/crates/proc-macro-srv/src/lib.rs b/crates/proc-macro-srv/src/lib.rs index 22afa018de..223c5a54b7 100644 --- a/crates/proc-macro-srv/src/lib.rs +++ b/crates/proc-macro-srv/src/lib.rs @@ -41,7 +41,7 @@ use std::{ }; use paths::{Utf8Path, Utf8PathBuf}; -use span::{ErasedFileAstId, FIXUP_ERASED_FILE_AST_ID_MARKER, Span, TokenId}; +use span::{Span, TokenId}; use crate::server_impl::TokenStream; @@ -57,16 +57,11 @@ pub const RUSTC_VERSION_STRING: &str = env!("RUSTC_VERSION"); pub struct ProcMacroSrv<'env> { expanders: Mutex>>, env: &'env EnvSnapshot, - fixup_ast_id: ErasedFileAstId, } impl<'env> ProcMacroSrv<'env> { pub fn new(env: &'env EnvSnapshot) -> Self { - Self { expanders: Default::default(), env, fixup_ast_id: FIXUP_ERASED_FILE_AST_ID_MARKER } - } - - pub fn set_fixup_ast_id(&mut self, fixup_ast_id: u32) { - self.fixup_ast_id = ErasedFileAstId::from_raw(fixup_ast_id); + Self { expanders: Default::default(), env } } } @@ -106,7 +101,6 @@ impl ProcMacroSrv<'_> { def_site, call_site, mixed_site, - self.fixup_ast_id, ) .map(|tt| tt.0) }); @@ -162,41 +156,25 @@ impl ProcMacroSrv<'_> { pub trait ProcMacroSrvSpan: Copy + Send { type Server: proc_macro::bridge::server::Server>; - fn make_server( - call_site: Self, - def_site: Self, - mixed_site: Self, - fixup_ast_id: ErasedFileAstId, - ) -> Self::Server; + fn make_server(call_site: Self, def_site: Self, mixed_site: Self) -> Self::Server; } impl ProcMacroSrvSpan for TokenId { type Server = server_impl::token_id::TokenIdServer; - fn make_server( - call_site: Self, - def_site: Self, - mixed_site: Self, - _fixup_ast_id: ErasedFileAstId, - ) -> Self::Server { + fn make_server(call_site: Self, def_site: Self, mixed_site: Self) -> Self::Server { Self::Server { call_site, def_site, mixed_site } } } impl ProcMacroSrvSpan for Span { type Server = server_impl::rust_analyzer_span::RaSpanServer; - fn make_server( - call_site: Self, - def_site: Self, - mixed_site: Self, - fixup_ast_id: ErasedFileAstId, - ) -> Self::Server { + fn make_server(call_site: Self, def_site: Self, mixed_site: Self) -> Self::Server { Self::Server { call_site, def_site, mixed_site, tracked_env_vars: Default::default(), tracked_paths: Default::default(), - fixup_ast_id, } } } diff --git a/crates/proc-macro-srv/src/proc_macros.rs b/crates/proc-macro-srv/src/proc_macros.rs index 3b9c45894c..18532706c4 100644 --- a/crates/proc-macro-srv/src/proc_macros.rs +++ b/crates/proc-macro-srv/src/proc_macros.rs @@ -1,7 +1,6 @@ //! Proc macro ABI use proc_macro::bridge; -use span::ErasedFileAstId; use crate::{ProcMacroKind, ProcMacroSrvSpan, server_impl::TopSubtree}; @@ -23,7 +22,6 @@ impl ProcMacros { def_site: S, call_site: S, mixed_site: S, - fixup_ast_id: ErasedFileAstId, ) -> Result, crate::PanicMessage> { let parsed_body = crate::server_impl::TokenStream::with_subtree(macro_body); @@ -39,7 +37,7 @@ impl ProcMacros { { let res = client.run( &bridge::server::SameThread, - S::make_server(call_site, def_site, mixed_site, fixup_ast_id), + S::make_server(call_site, def_site, mixed_site), parsed_body, cfg!(debug_assertions), ); @@ -50,7 +48,7 @@ impl ProcMacros { bridge::client::ProcMacro::Bang { name, client } if *name == macro_name => { let res = client.run( &bridge::server::SameThread, - S::make_server(call_site, def_site, mixed_site, fixup_ast_id), + S::make_server(call_site, def_site, mixed_site), parsed_body, cfg!(debug_assertions), ); @@ -61,7 +59,7 @@ impl ProcMacros { bridge::client::ProcMacro::Attr { name, client } if *name == macro_name => { let res = client.run( &bridge::server::SameThread, - S::make_server(call_site, def_site, mixed_site, fixup_ast_id), + S::make_server(call_site, def_site, mixed_site), parsed_attributes, parsed_body, cfg!(debug_assertions), diff --git a/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs b/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs index b071ad80f5..a1863efafb 100644 --- a/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs +++ b/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs @@ -11,7 +11,7 @@ use std::{ use intern::Symbol; use proc_macro::bridge::{self, server}; -use span::{ErasedFileAstId, Span}; +use span::{FIXUP_ERASED_FILE_AST_ID_MARKER, Span}; use tt::{TextRange, TextSize}; use crate::server_impl::{from_token_tree, literal_from_str, token_stream::TokenStreamBuilder}; @@ -28,7 +28,6 @@ pub struct RaSpanServer { pub call_site: Span, pub def_site: Span, pub mixed_site: Span, - pub fixup_ast_id: ErasedFileAstId, } impl server::Types for RaSpanServer { @@ -182,10 +181,10 @@ impl server::Span for RaSpanServer { fn join(&mut self, first: Self::Span, second: Self::Span) -> Option { // We can't modify the span range for fixup spans, those are meaningful to fixup, so just // prefer the non-fixup span. - if first.anchor.ast_id == self.fixup_ast_id { + if first.anchor.ast_id == FIXUP_ERASED_FILE_AST_ID_MARKER { return Some(second); } - if second.anchor.ast_id == self.fixup_ast_id { + if second.anchor.ast_id == FIXUP_ERASED_FILE_AST_ID_MARKER { return Some(first); } // FIXME: Once we can talk back to the client, implement a "long join" request for anchors @@ -214,7 +213,7 @@ impl server::Span for RaSpanServer { end: Bound, ) -> Option { // We can't modify the span range for fixup spans, those are meaningful to fixup. - if span.anchor.ast_id == self.fixup_ast_id { + if span.anchor.ast_id == FIXUP_ERASED_FILE_AST_ID_MARKER { return Some(span); } let length = span.range.len().into(); @@ -257,7 +256,7 @@ impl server::Span for RaSpanServer { fn end(&mut self, span: Self::Span) -> Self::Span { // We can't modify the span range for fixup spans, those are meaningful to fixup. - if span.anchor.ast_id == self.fixup_ast_id { + if span.anchor.ast_id == FIXUP_ERASED_FILE_AST_ID_MARKER { return span; } Span { range: TextRange::empty(span.range.end()), ..span } @@ -265,7 +264,7 @@ impl server::Span for RaSpanServer { fn start(&mut self, span: Self::Span) -> Self::Span { // We can't modify the span range for fixup spans, those are meaningful to fixup. - if span.anchor.ast_id == self.fixup_ast_id { + if span.anchor.ast_id == FIXUP_ERASED_FILE_AST_ID_MARKER { return span; } Span { range: TextRange::empty(span.range.start()), ..span } diff --git a/crates/proc-macro-srv/src/tests/utils.rs b/crates/proc-macro-srv/src/tests/utils.rs index e0a69608de..10af5662b5 100644 --- a/crates/proc-macro-srv/src/tests/utils.rs +++ b/crates/proc-macro-srv/src/tests/utils.rs @@ -2,8 +2,7 @@ use expect_test::Expect; use span::{ - EditionedFileId, FIXUP_ERASED_FILE_AST_ID_MARKER, FileId, ROOT_ERASED_FILE_AST_ID, Span, - SpanAnchor, SyntaxContext, TokenId, + EditionedFileId, FileId, ROOT_ERASED_FILE_AST_ID, Span, SpanAnchor, SyntaxContext, TokenId, }; use tt::TextRange; @@ -68,17 +67,8 @@ fn assert_expand_impl( let input_ts_string = format!("{input_ts:?}"); let attr_ts_string = attr_ts.as_ref().map(|it| format!("{it:?}")); - let res = expander - .expand( - macro_name, - input_ts, - attr_ts, - def_site, - call_site, - mixed_site, - FIXUP_ERASED_FILE_AST_ID_MARKER, - ) - .unwrap(); + let res = + expander.expand(macro_name, input_ts, attr_ts, def_site, call_site, mixed_site).unwrap(); expect.assert_eq(&format!( "{input_ts_string}\n\n{}\n\n{res:?}", attr_ts_string.unwrap_or_default() @@ -110,17 +100,7 @@ fn assert_expand_impl( let fixture_string = format!("{fixture:?}"); let attr_string = attr.as_ref().map(|it| format!("{it:?}")); - let res = expander - .expand( - macro_name, - fixture, - attr, - def_site, - call_site, - mixed_site, - FIXUP_ERASED_FILE_AST_ID_MARKER, - ) - .unwrap(); + let res = expander.expand(macro_name, fixture, attr, def_site, call_site, mixed_site).unwrap(); expect_spanned .assert_eq(&format!("{fixture_string}\n\n{}\n\n{res:#?}", attr_string.unwrap_or_default())); } diff --git a/crates/span/src/ast_id.rs b/crates/span/src/ast_id.rs index 51a693ca01..8e95971198 100644 --- a/crates/span/src/ast_id.rs +++ b/crates/span/src/ast_id.rs @@ -108,7 +108,8 @@ impl fmt::Debug for ErasedFileAstId { #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] enum ErasedFileAstIdKind { - Root, + /// This needs to not change because it's depended upon by the proc macro server. + Fixup, // The following are associated with `ErasedHasNameFileAstId`. Enum, Struct, @@ -143,7 +144,7 @@ enum ErasedFileAstIdKind { /// Associated with [`BlockExprFileAstId`]. BlockExpr, /// Keep this last. - Fixup, + Root, } // First hash, then index, then kind. @@ -218,7 +219,7 @@ impl ErasedFileAstId { } #[inline] - pub fn from_raw(v: u32) -> Self { + pub const fn from_raw(v: u32) -> Self { Self(v) } } From 4ed107fbc90cf073eabf19f50a662c1439897c0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 13 Jun 2025 07:55:07 +0200 Subject: [PATCH 29/56] Fix link to good first issues --- docs/book/src/contributing/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/book/src/contributing/README.md b/docs/book/src/contributing/README.md index 05286b5429..5f4a74eba2 100644 --- a/docs/book/src/contributing/README.md +++ b/docs/book/src/contributing/README.md @@ -30,7 +30,7 @@ Discussion happens in this Zulip stream: # Issue Labels -* [good-first-issue](https://github.com/rust-lang/rust-analyzer/labels/good%20first%20issue) +* [good-first-issue](https://github.com/rust-lang/rust-analyzer/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22good%20first%20issue%22) are good issues to get into the project. * [E-has-instructions](https://github.com/rust-lang/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%3AE-has-instructions) issues have links to the code in question and tests. From ace69d93e07ec736569cc9e64d935780637e0767 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 13 Jun 2025 08:09:44 +0200 Subject: [PATCH 30/56] Store item tree visibilities in a thin vec --- crates/hir-def/src/item_tree.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs index 90a5dd2dc7..85a43de6ff 100644 --- a/crates/hir-def/src/item_tree.rs +++ b/crates/hir-def/src/item_tree.rs @@ -56,6 +56,7 @@ use rustc_hash::FxHashMap; use span::{AstIdNode, Edition, FileAstId, SyntaxContext}; use stdx::never; use syntax::{SyntaxKind, ast, match_ast}; +use thin_vec::ThinVec; use triomphe::Arc; use crate::{BlockId, Lookup, attr::Attrs, db::DefDatabase}; @@ -144,7 +145,7 @@ pub(crate) fn block_item_tree_query(db: &dyn DefDatabase, block: BlockId) -> Arc attrs: FxHashMap::default(), data: FxHashMap::default(), top_attrs: RawAttrs::EMPTY, - vis: ItemVisibilities { arena: Box::new([]) }, + vis: ItemVisibilities { arena: ThinVec::new() }, }) }) .clone() @@ -229,29 +230,40 @@ impl ItemTree { #[derive(Default, Debug, Eq, PartialEq)] struct ItemVisibilities { - arena: Box<[RawVisibility]>, + arena: ThinVec, } #[derive(Debug, Clone, Eq, PartialEq)] enum ModItem { Const(Const), Enum(Enum), + // 32 ExternBlock(ExternBlock), + // 40 ExternCrate(ExternCrate), Function(Function), Impl(Impl), Macro2(Macro2), + // 32 MacroCall(MacroCall), MacroRules(MacroRules), + // 40 Mod(Mod), Static(Static), + // 32 Struct(Struct), Trait(Trait), TraitAlias(TraitAlias), TypeAlias(TypeAlias), Union(Union), + // 40 Use(Use), } + +// `ModItem` is stored a bunch in `ItemTree`'s so we pay the max for each item. It should stay as small as possible. +#[cfg(target_pointer_width = "64")] +const _: [(); std::mem::size_of::()] = [(); std::mem::size_of::<[usize; 5]>()]; + #[derive(Default, Debug, Eq, PartialEq)] pub struct ItemTreeDataStats { pub traits: usize, From 65e2e2c083486cb777e4156b33c89ee99b720c67 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 13 Jun 2025 08:24:50 +0200 Subject: [PATCH 31/56] Split mod items into small and big variants --- crates/hir-def/src/item_tree.rs | 103 +++++++++++++++----------- crates/hir-def/src/item_tree/lower.rs | 43 +++++------ crates/intern/src/symbol.rs | 1 - 3 files changed, 81 insertions(+), 66 deletions(-) diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs index 85a43de6ff..5b9da17231 100644 --- a/crates/hir-def/src/item_tree.rs +++ b/crates/hir-def/src/item_tree.rs @@ -133,7 +133,8 @@ pub(crate) fn block_item_tree_query(db: &dyn DefDatabase, block: BlockId) -> Arc let ctx = lower::Ctx::new(db, loc.ast_id.file_id); let mut item_tree = ctx.lower_block(&block); - if item_tree.data.is_empty() + if item_tree.small_data.is_empty() + && item_tree.big_data.is_empty() && item_tree.top_level.is_empty() && item_tree.attrs.is_empty() && item_tree.top_attrs.is_empty() @@ -143,7 +144,8 @@ pub(crate) fn block_item_tree_query(db: &dyn DefDatabase, block: BlockId) -> Arc Arc::new(ItemTree { top_level: Box::new([]), attrs: FxHashMap::default(), - data: FxHashMap::default(), + small_data: FxHashMap::default(), + big_data: FxHashMap::default(), top_attrs: RawAttrs::EMPTY, vis: ItemVisibilities { arena: ThinVec::new() }, }) @@ -162,7 +164,8 @@ pub struct ItemTree { attrs: FxHashMap, RawAttrs>, vis: ItemVisibilities, // FIXME: They values store the key, turn this into a FxHashSet instead? - data: FxHashMap, ModItem>, + big_data: FxHashMap, BigModItem>, + small_data: FxHashMap, SmallModItem>, } impl ItemTree { @@ -204,13 +207,18 @@ impl ItemTree { let mut mods = 0; let mut macro_calls = 0; let mut macro_rules = 0; - for item in self.data.values() { + for item in self.small_data.values() { match item { - ModItem::Trait(_) => traits += 1, - ModItem::Impl(_) => impls += 1, - ModItem::Mod(_) => mods += 1, - ModItem::MacroCall(_) => macro_calls += 1, - ModItem::MacroRules(_) => macro_rules += 1, + SmallModItem::Trait(_) => traits += 1, + SmallModItem::Impl(_) => impls += 1, + SmallModItem::MacroRules(_) => macro_rules += 1, + _ => {} + } + } + for item in self.big_data.values() { + match item { + BigModItem::Mod(_) => mods += 1, + BigModItem::MacroCall(_) => macro_calls += 1, _ => {} } } @@ -222,9 +230,10 @@ impl ItemTree { } fn shrink_to_fit(&mut self) { - let ItemTree { top_level: _, attrs, data, vis: _, top_attrs: _ } = self; + let ItemTree { top_level: _, attrs, big_data, small_data, vis: _, top_attrs: _ } = self; attrs.shrink_to_fit(); - data.shrink_to_fit(); + big_data.shrink_to_fit(); + small_data.shrink_to_fit(); } } @@ -234,35 +243,37 @@ struct ItemVisibilities { } #[derive(Debug, Clone, Eq, PartialEq)] -enum ModItem { +enum SmallModItem { Const(Const), Enum(Enum), - // 32 - ExternBlock(ExternBlock), - // 40 - ExternCrate(ExternCrate), Function(Function), Impl(Impl), Macro2(Macro2), - // 32 - MacroCall(MacroCall), MacroRules(MacroRules), - // 40 - Mod(Mod), Static(Static), - // 32 - Struct(Struct), Trait(Trait), TraitAlias(TraitAlias), TypeAlias(TypeAlias), Union(Union), - // 40 +} + +#[derive(Debug, Clone, Eq, PartialEq)] +enum BigModItem { + ExternBlock(ExternBlock), + ExternCrate(ExternCrate), + MacroCall(MacroCall), + Mod(Mod), + Struct(Struct), Use(Use), } -// `ModItem` is stored a bunch in `ItemTree`'s so we pay the max for each item. It should stay as small as possible. +// `ModItem` is stored a bunch in `ItemTree`'s so we pay the max for each item. It should stay as +// small as possible which is why we split them in two, most common ones are 3 usize but some rarer +// ones are 5. #[cfg(target_pointer_width = "64")] -const _: [(); std::mem::size_of::()] = [(); std::mem::size_of::<[usize; 5]>()]; +const _: [(); std::mem::size_of::()] = [(); std::mem::size_of::<[usize; 5]>()]; +#[cfg(target_pointer_width = "64")] +const _: [(); std::mem::size_of::()] = [(); std::mem::size_of::<[usize; 3]>()]; #[derive(Default, Debug, Eq, PartialEq)] pub struct ItemTreeDataStats { @@ -343,9 +354,12 @@ macro_rules! mod_items { impl Index> for ItemTree { type Output = $typ; + #[allow(unused_imports)] fn index(&self, index: FileAstId<$ast>) -> &Self::Output { - match &self.data[&index.upcast()] { - ModItem::$typ(item) => item, + use BigModItem::*; + use SmallModItem::*; + match &self.$fld[&index.upcast()] { + $typ(item) => item, _ => panic!("expected item of type `{}` at index `{:?}`", stringify!($typ), index), } } @@ -356,23 +370,23 @@ macro_rules! mod_items { mod_items! { ModItemId -> - Use in uses -> ast::Use, - ExternCrate in extern_crates -> ast::ExternCrate, - ExternBlock in extern_blocks -> ast::ExternBlock, - Function in functions -> ast::Fn, - Struct in structs -> ast::Struct, - Union in unions -> ast::Union, - Enum in enums -> ast::Enum, - Const in consts -> ast::Const, - Static in statics -> ast::Static, - Trait in traits -> ast::Trait, - TraitAlias in trait_aliases -> ast::TraitAlias, - Impl in impls -> ast::Impl, - TypeAlias in type_aliases -> ast::TypeAlias, - Mod in mods -> ast::Module, - MacroCall in macro_calls -> ast::MacroCall, - MacroRules in macro_rules -> ast::MacroRules, - Macro2 in macro_defs -> ast::MacroDef, + Use in big_data -> ast::Use, + ExternCrate in big_data -> ast::ExternCrate, + ExternBlock in big_data -> ast::ExternBlock, + Function in small_data -> ast::Fn, + Struct in big_data -> ast::Struct, + Union in small_data -> ast::Union, + Enum in small_data -> ast::Enum, + Const in small_data -> ast::Const, + Static in small_data -> ast::Static, + Trait in small_data -> ast::Trait, + TraitAlias in small_data -> ast::TraitAlias, + Impl in small_data -> ast::Impl, + TypeAlias in small_data -> ast::TypeAlias, + Mod in big_data -> ast::Module, + MacroCall in big_data -> ast::MacroCall, + MacroRules in small_data -> ast::MacroRules, + Macro2 in small_data -> ast::MacroDef, } impl Index for ItemTree { @@ -421,6 +435,7 @@ pub struct UseTree { } // FIXME: Would be nice to encode `None` into this +// We could just use a `Name` where `_` well means `_` .. #[derive(Debug, Clone, PartialEq, Eq)] pub enum ImportAlias { /// Unnamed alias, as in `use Foo as _;` diff --git a/crates/hir-def/src/item_tree/lower.rs b/crates/hir-def/src/item_tree/lower.rs index ab60b7ad70..6ae745bb9a 100644 --- a/crates/hir-def/src/item_tree/lower.rs +++ b/crates/hir-def/src/item_tree/lower.rs @@ -20,10 +20,11 @@ use triomphe::Arc; use crate::{ db::DefDatabase, item_tree::{ - Const, Enum, ExternBlock, ExternCrate, FieldsShape, Function, Impl, ImportAlias, Interned, - ItemTree, ItemTreeAstId, Macro2, MacroCall, MacroRules, Mod, ModItem, ModItemId, ModKind, - ModPath, RawAttrs, RawVisibility, RawVisibilityId, Static, Struct, StructKind, Trait, - TraitAlias, TypeAlias, Union, Use, UseTree, UseTreeKind, VisibilityExplicitness, + BigModItem, Const, Enum, ExternBlock, ExternCrate, FieldsShape, Function, Impl, + ImportAlias, Interned, ItemTree, ItemTreeAstId, Macro2, MacroCall, MacroRules, Mod, + ModItemId, ModKind, ModPath, RawAttrs, RawVisibility, RawVisibilityId, SmallModItem, + Static, Struct, StructKind, Trait, TraitAlias, TypeAlias, Union, Use, UseTree, UseTreeKind, + VisibilityExplicitness, }, }; @@ -168,7 +169,7 @@ impl<'a> Ctx<'a> { let ast_id = self.source_ast_id_map.ast_id(strukt); let shape = adt_shape(strukt.kind()); let res = Struct { name, visibility, shape, ast_id }; - self.tree.data.insert(ast_id.upcast(), ModItem::Struct(res)); + self.tree.big_data.insert(ast_id.upcast(), BigModItem::Struct(res)); Some(ast_id) } @@ -178,7 +179,7 @@ impl<'a> Ctx<'a> { let name = union.name()?.as_name(); let ast_id = self.source_ast_id_map.ast_id(union); let res = Union { name, visibility, ast_id }; - self.tree.data.insert(ast_id.upcast(), ModItem::Union(res)); + self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Union(res)); Some(ast_id) } @@ -187,7 +188,7 @@ impl<'a> Ctx<'a> { let name = enum_.name()?.as_name(); let ast_id = self.source_ast_id_map.ast_id(enum_); let res = Enum { name, visibility, ast_id }; - self.tree.data.insert(ast_id.upcast(), ModItem::Enum(res)); + self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Enum(res)); Some(ast_id) } @@ -199,7 +200,7 @@ impl<'a> Ctx<'a> { let res = Function { name, visibility, ast_id }; - self.tree.data.insert(ast_id.upcast(), ModItem::Function(res)); + self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Function(res)); Some(ast_id) } @@ -211,7 +212,7 @@ impl<'a> Ctx<'a> { let visibility = self.lower_visibility(type_alias); let ast_id = self.source_ast_id_map.ast_id(type_alias); let res = TypeAlias { name, visibility, ast_id }; - self.tree.data.insert(ast_id.upcast(), ModItem::TypeAlias(res)); + self.tree.small_data.insert(ast_id.upcast(), SmallModItem::TypeAlias(res)); Some(ast_id) } @@ -220,7 +221,7 @@ impl<'a> Ctx<'a> { let visibility = self.lower_visibility(static_); let ast_id = self.source_ast_id_map.ast_id(static_); let res = Static { name, visibility, ast_id }; - self.tree.data.insert(ast_id.upcast(), ModItem::Static(res)); + self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Static(res)); Some(ast_id) } @@ -229,7 +230,7 @@ impl<'a> Ctx<'a> { let visibility = self.lower_visibility(konst); let ast_id = self.source_ast_id_map.ast_id(konst); let res = Const { name, visibility, ast_id }; - self.tree.data.insert(ast_id.upcast(), ModItem::Const(res)); + self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Const(res)); ast_id } @@ -251,7 +252,7 @@ impl<'a> Ctx<'a> { }; let ast_id = self.source_ast_id_map.ast_id(module); let res = Mod { name, visibility, kind, ast_id }; - self.tree.data.insert(ast_id.upcast(), ModItem::Mod(res)); + self.tree.big_data.insert(ast_id.upcast(), BigModItem::Mod(res)); Some(ast_id) } @@ -261,7 +262,7 @@ impl<'a> Ctx<'a> { let ast_id = self.source_ast_id_map.ast_id(trait_def); let def = Trait { name, visibility, ast_id }; - self.tree.data.insert(ast_id.upcast(), ModItem::Trait(def)); + self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Trait(def)); Some(ast_id) } @@ -274,7 +275,7 @@ impl<'a> Ctx<'a> { let ast_id = self.source_ast_id_map.ast_id(trait_alias_def); let alias = TraitAlias { name, visibility, ast_id }; - self.tree.data.insert(ast_id.upcast(), ModItem::TraitAlias(alias)); + self.tree.small_data.insert(ast_id.upcast(), SmallModItem::TraitAlias(alias)); Some(ast_id) } @@ -283,7 +284,7 @@ impl<'a> Ctx<'a> { // 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 { ast_id }; - self.tree.data.insert(ast_id.upcast(), ModItem::Impl(res)); + self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Impl(res)); ast_id } @@ -295,7 +296,7 @@ impl<'a> Ctx<'a> { })?; let res = Use { visibility, ast_id, use_tree }; - self.tree.data.insert(ast_id.upcast(), ModItem::Use(res)); + self.tree.big_data.insert(ast_id.upcast(), BigModItem::Use(res)); Some(ast_id) } @@ -311,7 +312,7 @@ impl<'a> Ctx<'a> { let ast_id = self.source_ast_id_map.ast_id(extern_crate); let res = ExternCrate { name, alias, visibility, ast_id }; - self.tree.data.insert(ast_id.upcast(), ModItem::ExternCrate(res)); + self.tree.big_data.insert(ast_id.upcast(), BigModItem::ExternCrate(res)); Some(ast_id) } @@ -325,7 +326,7 @@ impl<'a> Ctx<'a> { let ast_id = self.source_ast_id_map.ast_id(m); let expand_to = hir_expand::ExpandTo::from_call_site(m); let res = MacroCall { path, ast_id, expand_to, ctxt: span_map.span_for_range(range).ctx }; - self.tree.data.insert(ast_id.upcast(), ModItem::MacroCall(res)); + self.tree.big_data.insert(ast_id.upcast(), BigModItem::MacroCall(res)); Some(ast_id) } @@ -334,7 +335,7 @@ impl<'a> Ctx<'a> { let ast_id = self.source_ast_id_map.ast_id(m); let res = MacroRules { name: name.as_name(), ast_id }; - self.tree.data.insert(ast_id.upcast(), ModItem::MacroRules(res)); + self.tree.small_data.insert(ast_id.upcast(), SmallModItem::MacroRules(res)); Some(ast_id) } @@ -345,7 +346,7 @@ impl<'a> Ctx<'a> { let visibility = self.lower_visibility(m); let res = Macro2 { name: name.as_name(), ast_id, visibility }; - self.tree.data.insert(ast_id.upcast(), ModItem::Macro2(res)); + self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Macro2(res)); Some(ast_id) } @@ -372,7 +373,7 @@ impl<'a> Ctx<'a> { }); let res = ExternBlock { ast_id, children }; - self.tree.data.insert(ast_id.upcast(), ModItem::ExternBlock(res)); + self.tree.big_data.insert(ast_id.upcast(), BigModItem::ExternBlock(res)); ast_id } diff --git a/crates/intern/src/symbol.rs b/crates/intern/src/symbol.rs index 3b962a86f1..8b2d6e8717 100644 --- a/crates/intern/src/symbol.rs +++ b/crates/intern/src/symbol.rs @@ -112,7 +112,6 @@ impl TaggedArcPtr { } } -// FIXME: This should have more than one niche #[derive(PartialEq, Eq, Hash)] pub struct Symbol { repr: TaggedArcPtr, From 048a01a05db0f359ec1f05e9d7d9c80b12432ad0 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 13 Jun 2025 08:43:56 +0200 Subject: [PATCH 32/56] Remove ast ids from item tree mod items --- crates/hir-def/src/item_tree.rs | 52 ++++------ crates/hir-def/src/item_tree/lower.rs | 40 ++++---- crates/hir-def/src/item_tree/pretty.rs | 68 ++++++------- crates/hir-def/src/nameres/collector.rs | 124 ++++++++++-------------- 4 files changed, 122 insertions(+), 162 deletions(-) diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs index 5b9da17231..bf482d33e7 100644 --- a/crates/hir-def/src/item_tree.rs +++ b/crates/hir-def/src/item_tree.rs @@ -212,13 +212,13 @@ impl ItemTree { SmallModItem::Trait(_) => traits += 1, SmallModItem::Impl(_) => impls += 1, SmallModItem::MacroRules(_) => macro_rules += 1, + SmallModItem::MacroCall(_) => macro_calls += 1, _ => {} } } for item in self.big_data.values() { match item { BigModItem::Mod(_) => mods += 1, - BigModItem::MacroCall(_) => macro_calls += 1, _ => {} } } @@ -246,11 +246,14 @@ struct ItemVisibilities { enum SmallModItem { Const(Const), Enum(Enum), + ExternBlock(ExternBlock), Function(Function), Impl(Impl), Macro2(Macro2), + MacroCall(MacroCall), MacroRules(MacroRules), Static(Static), + Struct(Struct), Trait(Trait), TraitAlias(TraitAlias), TypeAlias(TypeAlias), @@ -259,11 +262,8 @@ enum SmallModItem { #[derive(Debug, Clone, Eq, PartialEq)] enum BigModItem { - ExternBlock(ExternBlock), ExternCrate(ExternCrate), - MacroCall(MacroCall), Mod(Mod), - Struct(Struct), Use(Use), } @@ -370,23 +370,23 @@ macro_rules! mod_items { mod_items! { ModItemId -> - Use in big_data -> ast::Use, - ExternCrate in big_data -> ast::ExternCrate, - ExternBlock in big_data -> ast::ExternBlock, - Function in small_data -> ast::Fn, - Struct in big_data -> ast::Struct, - Union in small_data -> ast::Union, - Enum in small_data -> ast::Enum, Const in small_data -> ast::Const, + Enum in small_data -> ast::Enum, + ExternBlock in small_data -> ast::ExternBlock, + ExternCrate in big_data -> ast::ExternCrate, + Function in small_data -> ast::Fn, + Impl in small_data -> ast::Impl, + Macro2 in small_data -> ast::MacroDef, + MacroCall in small_data -> ast::MacroCall, + MacroRules in small_data -> ast::MacroRules, + Mod in big_data -> ast::Module, Static in small_data -> ast::Static, + Struct in small_data -> ast::Struct, Trait in small_data -> ast::Trait, TraitAlias in small_data -> ast::TraitAlias, - Impl in small_data -> ast::Impl, TypeAlias in small_data -> ast::TypeAlias, - Mod in big_data -> ast::Module, - MacroCall in big_data -> ast::MacroCall, - MacroRules in small_data -> ast::MacroRules, - Macro2 in small_data -> ast::MacroDef, + Union in small_data -> ast::Union, + Use in big_data -> ast::Use, } impl Index for ItemTree { @@ -425,7 +425,6 @@ impl Index for ItemTree { #[derive(Debug, Clone, Eq, PartialEq)] pub struct Use { pub(crate) visibility: RawVisibilityId, - pub(crate) ast_id: FileAstId, pub(crate) use_tree: UseTree, } @@ -490,12 +489,10 @@ pub struct ExternCrate { pub name: Name, pub alias: Option, pub(crate) visibility: RawVisibilityId, - pub ast_id: FileAstId, } #[derive(Debug, Clone, Eq, PartialEq)] pub struct ExternBlock { - pub ast_id: FileAstId, pub(crate) children: Box<[ModItemId]>, } @@ -503,7 +500,6 @@ pub struct ExternBlock { pub struct Function { pub name: Name, pub(crate) visibility: RawVisibilityId, - pub ast_id: FileAstId, } #[derive(Debug, Clone, Eq, PartialEq)] @@ -511,21 +507,18 @@ pub struct Struct { pub name: Name, pub(crate) visibility: RawVisibilityId, pub shape: FieldsShape, - pub ast_id: FileAstId, } #[derive(Debug, Clone, Eq, PartialEq)] pub struct Union { pub name: Name, pub(crate) visibility: RawVisibilityId, - pub ast_id: FileAstId, } #[derive(Debug, Clone, Eq, PartialEq)] pub struct Enum { pub name: Name, pub(crate) visibility: RawVisibilityId, - pub ast_id: FileAstId, } #[derive(Debug, Copy, Clone, PartialEq, Eq)] @@ -564,40 +557,33 @@ pub struct Const { /// `None` for `const _: () = ();` pub name: Option, pub(crate) visibility: RawVisibilityId, - pub ast_id: FileAstId, } #[derive(Debug, Clone, Eq, PartialEq)] pub struct Static { pub name: Name, pub(crate) visibility: RawVisibilityId, - pub ast_id: FileAstId, } #[derive(Debug, Clone, Eq, PartialEq)] pub struct Trait { pub name: Name, pub(crate) visibility: RawVisibilityId, - pub ast_id: FileAstId, } #[derive(Debug, Clone, Eq, PartialEq)] pub struct TraitAlias { pub name: Name, pub(crate) visibility: RawVisibilityId, - pub ast_id: FileAstId, } #[derive(Debug, Clone, Eq, PartialEq)] -pub struct Impl { - pub ast_id: FileAstId, -} +pub struct Impl {} #[derive(Debug, Clone, PartialEq, Eq)] pub struct TypeAlias { pub name: Name, pub(crate) visibility: RawVisibilityId, - pub ast_id: FileAstId, } #[derive(Debug, Clone, Eq, PartialEq)] @@ -605,7 +591,6 @@ pub struct Mod { pub name: Name, pub(crate) visibility: RawVisibilityId, pub(crate) kind: ModKind, - pub ast_id: FileAstId, } #[derive(Debug, Clone, Eq, PartialEq)] @@ -620,7 +605,6 @@ pub(crate) enum ModKind { pub struct MacroCall { /// Path to the called macro. pub path: Interned, - pub ast_id: FileAstId, pub expand_to: ExpandTo, pub ctxt: SyntaxContext, } @@ -629,7 +613,6 @@ pub struct MacroCall { pub struct MacroRules { /// The name of the declared macro. pub name: Name, - pub ast_id: FileAstId, } /// "Macros 2.0" macro definition. @@ -637,7 +620,6 @@ pub struct MacroRules { pub struct Macro2 { pub name: Name, pub(crate) visibility: RawVisibilityId, - pub ast_id: FileAstId, } #[derive(Clone, Copy, Debug, Eq, PartialEq)] diff --git a/crates/hir-def/src/item_tree/lower.rs b/crates/hir-def/src/item_tree/lower.rs index 6ae745bb9a..fe1b8e3134 100644 --- a/crates/hir-def/src/item_tree/lower.rs +++ b/crates/hir-def/src/item_tree/lower.rs @@ -168,8 +168,8 @@ impl<'a> Ctx<'a> { let name = strukt.name()?.as_name(); let ast_id = self.source_ast_id_map.ast_id(strukt); let shape = adt_shape(strukt.kind()); - let res = Struct { name, visibility, shape, ast_id }; - self.tree.big_data.insert(ast_id.upcast(), BigModItem::Struct(res)); + let res = Struct { name, visibility, shape }; + self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Struct(res)); Some(ast_id) } @@ -178,7 +178,7 @@ impl<'a> Ctx<'a> { let visibility = self.lower_visibility(union); let name = union.name()?.as_name(); let ast_id = self.source_ast_id_map.ast_id(union); - let res = Union { name, visibility, ast_id }; + let res = Union { name, visibility }; self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Union(res)); Some(ast_id) } @@ -187,7 +187,7 @@ 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 res = Enum { name, visibility, ast_id }; + let res = Enum { name, visibility }; self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Enum(res)); Some(ast_id) } @@ -198,7 +198,7 @@ impl<'a> Ctx<'a> { let ast_id = self.source_ast_id_map.ast_id(func); - let res = Function { name, visibility, ast_id }; + let res = Function { name, visibility }; self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Function(res)); Some(ast_id) @@ -211,7 +211,7 @@ impl<'a> Ctx<'a> { let name = type_alias.name()?.as_name(); let visibility = self.lower_visibility(type_alias); let ast_id = self.source_ast_id_map.ast_id(type_alias); - let res = TypeAlias { name, visibility, ast_id }; + let res = TypeAlias { name, visibility }; self.tree.small_data.insert(ast_id.upcast(), SmallModItem::TypeAlias(res)); Some(ast_id) } @@ -220,7 +220,7 @@ impl<'a> Ctx<'a> { let name = static_.name()?.as_name(); let visibility = self.lower_visibility(static_); let ast_id = self.source_ast_id_map.ast_id(static_); - let res = Static { name, visibility, ast_id }; + let res = Static { name, visibility }; self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Static(res)); Some(ast_id) } @@ -229,7 +229,7 @@ impl<'a> Ctx<'a> { let name = konst.name().map(|it| it.as_name()); let visibility = self.lower_visibility(konst); let ast_id = self.source_ast_id_map.ast_id(konst); - let res = Const { name, visibility, ast_id }; + let res = Const { name, visibility }; self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Const(res)); ast_id } @@ -251,7 +251,7 @@ impl<'a> Ctx<'a> { } }; let ast_id = self.source_ast_id_map.ast_id(module); - let res = Mod { name, visibility, kind, ast_id }; + let res = Mod { name, visibility, kind }; self.tree.big_data.insert(ast_id.upcast(), BigModItem::Mod(res)); Some(ast_id) } @@ -261,7 +261,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 def = Trait { name, visibility, ast_id }; + let def = Trait { name, visibility }; self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Trait(def)); Some(ast_id) } @@ -274,7 +274,7 @@ impl<'a> Ctx<'a> { let visibility = self.lower_visibility(trait_alias_def); let ast_id = self.source_ast_id_map.ast_id(trait_alias_def); - let alias = TraitAlias { name, visibility, ast_id }; + let alias = TraitAlias { name, visibility }; self.tree.small_data.insert(ast_id.upcast(), SmallModItem::TraitAlias(alias)); Some(ast_id) } @@ -283,7 +283,7 @@ impl<'a> Ctx<'a> { let ast_id = self.source_ast_id_map.ast_id(impl_def); // 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 { ast_id }; + let res = Impl {}; self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Impl(res)); ast_id } @@ -295,7 +295,7 @@ impl<'a> Ctx<'a> { self.span_map().span_for_range(range).ctx })?; - let res = Use { visibility, ast_id, use_tree }; + let res = Use { visibility, use_tree }; self.tree.big_data.insert(ast_id.upcast(), BigModItem::Use(res)); Some(ast_id) } @@ -311,7 +311,7 @@ impl<'a> Ctx<'a> { let visibility = self.lower_visibility(extern_crate); let ast_id = self.source_ast_id_map.ast_id(extern_crate); - let res = ExternCrate { name, alias, visibility, ast_id }; + let res = ExternCrate { name, alias, visibility }; self.tree.big_data.insert(ast_id.upcast(), BigModItem::ExternCrate(res)); Some(ast_id) } @@ -325,8 +325,8 @@ impl<'a> Ctx<'a> { })?); let ast_id = self.source_ast_id_map.ast_id(m); let expand_to = hir_expand::ExpandTo::from_call_site(m); - let res = MacroCall { path, ast_id, expand_to, ctxt: span_map.span_for_range(range).ctx }; - self.tree.big_data.insert(ast_id.upcast(), BigModItem::MacroCall(res)); + let res = MacroCall { path, expand_to, ctxt: span_map.span_for_range(range).ctx }; + self.tree.small_data.insert(ast_id.upcast(), SmallModItem::MacroCall(res)); Some(ast_id) } @@ -334,7 +334,7 @@ impl<'a> Ctx<'a> { let name = m.name()?; let ast_id = self.source_ast_id_map.ast_id(m); - let res = MacroRules { name: name.as_name(), ast_id }; + let res = MacroRules { name: name.as_name() }; self.tree.small_data.insert(ast_id.upcast(), SmallModItem::MacroRules(res)); Some(ast_id) } @@ -345,7 +345,7 @@ impl<'a> Ctx<'a> { let ast_id = self.source_ast_id_map.ast_id(m); let visibility = self.lower_visibility(m); - let res = Macro2 { name: name.as_name(), ast_id, visibility }; + let res = Macro2 { name: name.as_name(), visibility }; self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Macro2(res)); Some(ast_id) } @@ -372,8 +372,8 @@ impl<'a> Ctx<'a> { .collect() }); - let res = ExternBlock { ast_id, children }; - self.tree.big_data.insert(ast_id.upcast(), BigModItem::ExternBlock(res)); + let res = ExternBlock { children }; + self.tree.small_data.insert(ast_id.upcast(), SmallModItem::ExternBlock(res)); ast_id } diff --git a/crates/hir-def/src/item_tree/pretty.rs b/crates/hir-def/src/item_tree/pretty.rs index 11b9156898..eb97081128 100644 --- a/crates/hir-def/src/item_tree/pretty.rs +++ b/crates/hir-def/src/item_tree/pretty.rs @@ -161,16 +161,16 @@ impl Printer<'_> { self.print_attrs_of(item, "\n"); match item { - ModItemId::Use(it) => { - let Use { visibility, use_tree, ast_id } = &self.tree[it]; + ModItemId::Use(ast_id) => { + let Use { visibility, use_tree } = &self.tree[ast_id]; self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); w!(self, "use "); self.print_use_tree(use_tree); wln!(self, ";"); } - ModItemId::ExternCrate(it) => { - let ExternCrate { name, alias, visibility, ast_id } = &self.tree[it]; + ModItemId::ExternCrate(ast_id) => { + let ExternCrate { name, alias, visibility } = &self.tree[ast_id]; self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); w!(self, "extern crate {}", name.display(self.db, self.edition)); @@ -179,8 +179,8 @@ impl Printer<'_> { } wln!(self, ";"); } - ModItemId::ExternBlock(it) => { - let ExternBlock { ast_id, children } = &self.tree[it]; + ModItemId::ExternBlock(ast_id) => { + let ExternBlock { children } = &self.tree[ast_id]; self.print_ast_id(ast_id.erase()); w!(self, "extern {{"); self.indented(|this| { @@ -190,14 +190,14 @@ impl Printer<'_> { }); wln!(self, "}}"); } - ModItemId::Function(it) => { - let Function { name, visibility, ast_id } = &self.tree[it]; + ModItemId::Function(ast_id) => { + let Function { name, visibility } = &self.tree[ast_id]; self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); wln!(self, "fn {};", name.display(self.db, self.edition)); } - ModItemId::Struct(it) => { - let Struct { visibility, name, shape: kind, ast_id } = &self.tree[it]; + ModItemId::Struct(ast_id) => { + let Struct { visibility, name, shape: kind } = &self.tree[ast_id]; self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); w!(self, "struct {}", name.display(self.db, self.edition)); @@ -208,22 +208,22 @@ impl Printer<'_> { wln!(self, ";"); } } - ModItemId::Union(it) => { - let Union { name, visibility, ast_id } = &self.tree[it]; + ModItemId::Union(ast_id) => { + let Union { name, visibility } = &self.tree[ast_id]; self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); w!(self, "union {}", name.display(self.db, self.edition)); self.print_fields(FieldsShape::Record); wln!(self); } - ModItemId::Enum(it) => { - let Enum { name, visibility, ast_id } = &self.tree[it]; + ModItemId::Enum(ast_id) => { + let Enum { name, visibility } = &self.tree[ast_id]; self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); w!(self, "enum {} {{ ... }}", name.display(self.db, self.edition)); } - ModItemId::Const(it) => { - let Const { name, visibility, ast_id } = &self.tree[it]; + ModItemId::Const(ast_id) => { + let Const { name, visibility } = &self.tree[ast_id]; self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); w!(self, "const "); @@ -233,8 +233,8 @@ impl Printer<'_> { } wln!(self, " = _;"); } - ModItemId::Static(it) => { - let Static { name, visibility, ast_id } = &self.tree[it]; + ModItemId::Static(ast_id) => { + let Static { name, visibility } = &self.tree[ast_id]; self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); w!(self, "static "); @@ -242,33 +242,33 @@ impl Printer<'_> { w!(self, " = _;"); wln!(self); } - ModItemId::Trait(it) => { - let Trait { name, visibility, ast_id } = &self.tree[it]; + ModItemId::Trait(ast_id) => { + let Trait { name, visibility } = &self.tree[ast_id]; self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); w!(self, "trait {} {{ ... }}", name.display(self.db, self.edition)); } - ModItemId::TraitAlias(it) => { - let TraitAlias { name, visibility, ast_id } = &self.tree[it]; + ModItemId::TraitAlias(ast_id) => { + let TraitAlias { name, visibility } = &self.tree[ast_id]; self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); wln!(self, "trait {} = ..;", name.display(self.db, self.edition)); } - ModItemId::Impl(it) => { - let Impl { ast_id } = &self.tree[it]; + ModItemId::Impl(ast_id) => { + let Impl {} = &self.tree[ast_id]; self.print_ast_id(ast_id.erase()); w!(self, "impl {{ ... }}"); } - ModItemId::TypeAlias(it) => { - let TypeAlias { name, visibility, ast_id } = &self.tree[it]; + ModItemId::TypeAlias(ast_id) => { + let TypeAlias { name, visibility } = &self.tree[ast_id]; self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); w!(self, "type {}", name.display(self.db, self.edition)); w!(self, ";"); wln!(self); } - ModItemId::Mod(it) => { - let Mod { name, visibility, kind, ast_id } = &self.tree[it]; + ModItemId::Mod(ast_id) => { + let Mod { name, visibility, kind } = &self.tree[ast_id]; self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); w!(self, "mod {}", name.display(self.db, self.edition)); @@ -287,8 +287,8 @@ impl Printer<'_> { } } } - ModItemId::MacroCall(it) => { - let MacroCall { path, ast_id, expand_to, ctxt } = &self.tree[it]; + ModItemId::MacroCall(ast_id) => { + let MacroCall { path, expand_to, ctxt } = &self.tree[ast_id]; let _ = writeln!( self, "// AstId: {:#?}, SyntaxContextId: {}, ExpandTo: {:?}", @@ -298,13 +298,13 @@ impl Printer<'_> { ); wln!(self, "{}!(...);", path.display(self.db, self.edition)); } - ModItemId::MacroRules(it) => { - let MacroRules { name, ast_id } = &self.tree[it]; + ModItemId::MacroRules(ast_id) => { + let MacroRules { name } = &self.tree[ast_id]; self.print_ast_id(ast_id.erase()); wln!(self, "macro_rules! {} {{ ... }}", name.display(self.db, self.edition)); } - ModItemId::Macro2(it) => { - let Macro2 { name, visibility, ast_id } = &self.tree[it]; + ModItemId::Macro2(ast_id) => { + let Macro2 { name, visibility } = &self.tree[ast_id]; self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); wln!(self, "macro {} {{ ... }}", name.display(self.db, self.edition)); diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index 3b2488c8ea..185cc0596b 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -1434,11 +1434,10 @@ impl DefCollector<'_> { // normal (as that would just be an identity expansion with extra output) // Instead we treat derive attributes special and apply them separately. - let item_tree = tree.item_tree(self.db); let ast_adt_id: FileAstId = match *mod_item { - ModItemId::Struct(strukt) => item_tree[strukt].ast_id.upcast(), - ModItemId::Union(union) => item_tree[union].ast_id.upcast(), - ModItemId::Enum(enum_) => item_tree[enum_].ast_id.upcast(), + ModItemId::Struct(ast_id) => ast_id.upcast(), + ModItemId::Union(ast_id) => ast_id.upcast(), + ModItemId::Enum(ast_id) => ast_id.upcast(), _ => { let diag = DefDiagnostic::invalid_derive_target( directive.module_id, @@ -1750,11 +1749,9 @@ impl ModCollector<'_, '_> { match item { ModItemId::Mod(m) => self.collect_module(m, &attrs), ModItemId::Use(item_tree_id) => { - let id = UseLoc { - container: module, - id: InFile::new(self.file_id(), self.item_tree[item_tree_id].ast_id), - } - .intern(db); + let id = + UseLoc { container: module, id: InFile::new(self.file_id(), item_tree_id) } + .intern(db); let is_prelude = attrs.by_key(sym::prelude_import).exists(); Import::from_use( self.item_tree, @@ -1772,12 +1769,12 @@ impl ModCollector<'_, '_> { ) } ModItemId::ExternCrate(item_tree_id) => { - let item_tree::ExternCrate { name, visibility, alias, ast_id } = + let item_tree::ExternCrate { name, visibility, alias } = &self.item_tree[item_tree_id]; let id = ExternCrateLoc { container: module, - id: InFile::new(self.tree_id.file_id(), *ast_id), + id: InFile::new(self.tree_id.file_id(), item_tree_id), } .intern(db); def_map.modules[self.module_id].scope.define_extern_crate_decl(id); @@ -1840,7 +1837,7 @@ impl ModCollector<'_, '_> { self.def_collector.def_map.diagnostics.push( DefDiagnostic::unresolved_extern_crate( module_id, - InFile::new(self.file_id(), *ast_id), + InFile::new(self.file_id(), item_tree_id), ), ); } @@ -1848,7 +1845,7 @@ impl ModCollector<'_, '_> { ModItemId::ExternBlock(block) => { let extern_block_id = ExternBlockLoc { container: module, - id: InFile::new(self.file_id(), self.item_tree[block].ast_id), + id: InFile::new(self.file_id(), block), } .intern(db); self.def_collector.def_map.modules[self.module_id] @@ -1859,26 +1856,20 @@ impl ModCollector<'_, '_> { ItemContainerId::ExternBlockId(extern_block_id), ) } - ModItemId::MacroCall(mac) => { - self.collect_macro_call(&self.item_tree[mac], container) - } + ModItemId::MacroCall(mac) => self.collect_macro_call(mac, container), ModItemId::MacroRules(id) => self.collect_macro_rules(id, module), ModItemId::Macro2(id) => self.collect_macro_def(id, module), ModItemId::Impl(imp) => { - let impl_id = ImplLoc { - container: module, - id: InFile::new(self.file_id(), self.item_tree[imp].ast_id), - } - .intern(db); + let impl_id = + ImplLoc { container: module, id: InFile::new(self.file_id(), imp) } + .intern(db); self.def_collector.def_map.modules[self.module_id].scope.define_impl(impl_id) } ModItemId::Function(id) => { let it = &self.item_tree[id]; - let fn_id = FunctionLoc { - container, - id: InFile::new(self.tree_id.file_id(), it.ast_id), - } - .intern(db); + let fn_id = + FunctionLoc { container, id: InFile::new(self.tree_id.file_id(), id) } + .intern(db); let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]); @@ -1889,7 +1880,7 @@ impl ModCollector<'_, '_> { if let Some(proc_macro) = attrs.parse_proc_macro_decl(&it.name) { self.def_collector.export_proc_macro( proc_macro, - InFile::new(self.file_id(), self.item_tree[id].ast_id), + InFile::new(self.file_id(), id), fn_id, ); } @@ -1903,7 +1894,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: InFile::new(self.file_id(), it.ast_id) } + StructLoc { container: module, id: InFile::new(self.file_id(), id) } .intern(db) .into(), &it.name, @@ -1917,7 +1908,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: InFile::new(self.file_id(), it.ast_id) } + UnionLoc { container: module, id: InFile::new(self.file_id(), id) } .intern(db) .into(), &it.name, @@ -1927,11 +1918,9 @@ impl ModCollector<'_, '_> { } ModItemId::Enum(id) => { let it = &self.item_tree[id]; - let enum_ = EnumLoc { - container: module, - id: InFile::new(self.tree_id.file_id(), it.ast_id), - } - .intern(db); + let enum_ = + EnumLoc { container: module, id: InFile::new(self.tree_id.file_id(), 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); @@ -1939,7 +1928,7 @@ impl ModCollector<'_, '_> { ModItemId::Const(id) => { let it = &self.item_tree[id]; let const_id = - ConstLoc { container, id: InFile::new(self.tree_id.file_id(), it.ast_id) } + ConstLoc { container, id: InFile::new(self.tree_id.file_id(), id) } .intern(db); match &it.name { @@ -1962,7 +1951,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: InFile::new(self.file_id(), it.ast_id) } + StaticLoc { container, id: InFile::new(self.file_id(), id) } .intern(db) .into(), &it.name, @@ -1976,7 +1965,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: InFile::new(self.file_id(), it.ast_id) } + TraitLoc { container: module, id: InFile::new(self.file_id(), id) } .intern(db) .into(), &it.name, @@ -1990,12 +1979,9 @@ 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: InFile::new(self.file_id(), it.ast_id), - } - .intern(db) - .into(), + TraitAliasLoc { container: module, id: InFile::new(self.file_id(), id) } + .intern(db) + .into(), &it.name, vis, false, @@ -2007,7 +1993,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: InFile::new(self.file_id(), it.ast_id) } + TypeAliasLoc { container, id: InFile::new(self.file_id(), id) } .intern(db) .into(), &it.name, @@ -2070,16 +2056,16 @@ impl ModCollector<'_, '_> { ); } - fn collect_module(&mut self, module_id: ItemTreeAstId, attrs: &Attrs) { + fn collect_module(&mut self, module_ast_id: ItemTreeAstId, attrs: &Attrs) { let path_attr = attrs.by_key(sym::path).string_value_unescape(); let is_macro_use = attrs.by_key(sym::macro_use).exists(); - let module = &self.item_tree[module_id]; + let module = &self.item_tree[module_ast_id]; match &module.kind { // inline module, just recurse ModKind::Inline { items } => { let module_id = self.push_child_module( module.name.clone(), - module.ast_id, + module_ast_id, None, &self.item_tree[module.visibility], ); @@ -2104,7 +2090,7 @@ impl ModCollector<'_, '_> { } // out of line module, resolve, parse and recurse ModKind::Outline => { - let ast_id = AstId::new(self.file_id(), module.ast_id); + let ast_id = AstId::new(self.file_id(), module_ast_id); let db = self.def_collector.db; match self.mod_dir.resolve_declaration( db, @@ -2123,10 +2109,7 @@ impl ModCollector<'_, '_> { match is_enabled { Err(cfg) => { self.emit_unconfigured_diagnostic( - InFile::new( - self.file_id(), - self.item_tree[module_id].ast_id.erase(), - ), + InFile::new(self.file_id(), module_ast_id.erase()), &cfg, ); } @@ -2295,11 +2278,11 @@ impl ModCollector<'_, '_> { Ok(()) } - fn collect_macro_rules(&mut self, id: ItemTreeAstId, module: ModuleId) { + fn collect_macro_rules(&mut self, ast_id: ItemTreeAstId, module: ModuleId) { let krate = self.def_collector.def_map.krate; - let mac = &self.item_tree[id]; - let attrs = self.item_tree.attrs(self.def_collector.db, krate, id.upcast()); - let ast_id = InFile::new(self.file_id(), mac.ast_id.upcast()); + let mac = &self.item_tree[ast_id]; + let attrs = self.item_tree.attrs(self.def_collector.db, krate, ast_id.upcast()); + let f_ast_id = InFile::new(self.file_id(), ast_id.upcast()); let export_attr = || attrs.by_key(sym::macro_export); @@ -2346,7 +2329,7 @@ impl ModCollector<'_, '_> { self.def_collector .def_map .diagnostics - .push(DefDiagnostic::unimplemented_builtin_macro(self.module_id, ast_id)); + .push(DefDiagnostic::unimplemented_builtin_macro(self.module_id, f_ast_id)); return; } } @@ -2362,16 +2345,13 @@ impl ModCollector<'_, '_> { let macro_id = MacroRulesLoc { container: module, - id: InFile::new(self.file_id(), mac.ast_id), + id: InFile::new(self.file_id(), ast_id), flags, expander, edition: self.def_collector.def_map.data.edition, } .intern(self.def_collector.db); - self.def_collector.def_map.macro_def_to_macro_id.insert( - InFile::new(self.file_id(), self.item_tree[id].ast_id).erase(), - macro_id.into(), - ); + self.def_collector.def_map.macro_def_to_macro_id.insert(f_ast_id.erase(), macro_id.into()); self.def_collector.define_macro_rules( self.module_id, mac.name.clone(), @@ -2380,14 +2360,14 @@ impl ModCollector<'_, '_> { ); } - fn collect_macro_def(&mut self, id: ItemTreeAstId, module: ModuleId) { + fn collect_macro_def(&mut self, ast_id: ItemTreeAstId, module: ModuleId) { let krate = self.def_collector.def_map.krate; - let mac = &self.item_tree[id]; - let ast_id = InFile::new(self.file_id(), mac.ast_id.upcast()); + let mac = &self.item_tree[ast_id]; + let attrs = self.item_tree.attrs(self.def_collector.db, krate, ast_id.upcast()); + let f_ast_id = InFile::new(self.file_id(), ast_id.upcast()); // Case 1: builtin macros let mut helpers_opt = None; - let attrs = self.item_tree.attrs(self.def_collector.db, krate, id.upcast()); let expander = if attrs.by_key(sym::rustc_builtin_macro).exists() { if let Some(expander) = find_builtin_macro(&mac.name) { match expander { @@ -2419,7 +2399,7 @@ impl ModCollector<'_, '_> { self.def_collector .def_map .diagnostics - .push(DefDiagnostic::unimplemented_builtin_macro(self.module_id, ast_id)); + .push(DefDiagnostic::unimplemented_builtin_macro(self.module_id, f_ast_id)); return; } } else { @@ -2430,16 +2410,13 @@ impl ModCollector<'_, '_> { let macro_id = Macro2Loc { container: module, - id: InFile::new(self.file_id(), mac.ast_id), + id: InFile::new(self.file_id(), ast_id), expander, allow_internal_unsafe, edition: self.def_collector.def_map.data.edition, } .intern(self.def_collector.db); - self.def_collector.def_map.macro_def_to_macro_id.insert( - InFile::new(self.file_id(), self.item_tree[id].ast_id).erase(), - macro_id.into(), - ); + self.def_collector.def_map.macro_def_to_macro_id.insert(f_ast_id.erase(), macro_id.into()); self.def_collector.define_macro_def( self.module_id, mac.name.clone(), @@ -2458,9 +2435,10 @@ impl ModCollector<'_, '_> { fn collect_macro_call( &mut self, - &MacroCall { ref path, ast_id, expand_to, ctxt }: &MacroCall, + ast_id: FileAstId, container: ItemContainerId, ) { + let &MacroCall { ref path, expand_to, ctxt } = &self.item_tree[ast_id]; let ast_id = AstIdWithPath::new(self.file_id(), ast_id, path.clone()); let db = self.def_collector.db; From 95d5091a09f1ae92cfa59c1b8ccee1dd45053883 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 13 Jun 2025 09:45:04 +0200 Subject: [PATCH 33/56] `cargo update` Updating adler2 v2.0.0 -> v2.0.1 Updating anyhow v1.0.97 -> v1.0.98 Updating bitflags v2.9.0 -> v2.9.1 Updating borsh v1.5.5 -> v1.5.7 Updating boxcar v0.2.12 -> v0.2.13 Updating camino v1.1.9 -> v1.1.10 Updating cc v1.2.16 -> v1.2.26 Updating cfg-if v1.0.0 -> v1.0.1 Updating flate2 v1.1.1 -> v1.1.2 Updating foldhash v0.1.4 -> v0.1.5 Updating getrandom v0.2.15 -> v0.2.16 Updating hashbrown v0.15.2 -> v0.15.4 Updating hermit-abi v0.3.9 -> v0.5.2 Updating icu_collections v1.5.0 -> v2.0.0 Adding icu_locale_core v2.0.0 Removing icu_locid v1.5.0 Removing icu_locid_transform v1.5.0 Removing icu_locid_transform_data v1.5.0 Updating icu_normalizer v1.5.0 -> v2.0.0 Updating icu_normalizer_data v1.5.0 -> v2.0.0 Updating icu_properties v1.5.1 -> v2.0.1 Updating icu_properties_data v1.5.0 -> v2.0.1 Updating icu_provider v1.5.0 -> v2.0.0 Removing icu_provider_macros v1.5.0 Updating idna_adapter v1.2.0 -> v1.2.1 Updating kqueue v1.0.8 -> v1.1.1 Updating libloading v0.8.7 -> v0.8.8 Updating libmimalloc-sys v0.1.40 -> v0.1.42 Updating litemap v0.7.5 -> v0.8.0 Updating lock_api v0.4.12 -> v0.4.13 Updating log v0.4.26 -> v0.4.27 Updating memchr v2.7.4 -> v2.7.5 Updating mimalloc v0.1.44 -> v0.1.46 Updating miniz_oxide v0.8.5 -> v0.8.9 Updating mio v1.0.3 -> v1.0.4 Updating num_cpus v1.16.0 -> v1.17.0 Updating once_cell v1.21.1 -> v1.21.3 Updating parking_lot v0.12.3 -> v0.12.4 Updating parking_lot_core v0.9.10 -> v0.9.11 Updating portable-atomic v1.11.0 -> v1.11.1 Adding potential_utf v0.1.2 Updating proc-macro2 v1.0.94 -> v1.0.95 Updating redox_syscall v0.5.10 -> v0.5.13 Updating rustc-demangle v0.1.24 -> v0.1.25 Updating rustc_apfloat v0.2.2+llvm-462a31f5a5ab -> v0.2.3+llvm-462a31f5a5ab Updating serde_spanned v0.6.8 -> v0.6.9 Updating smallvec v1.14.0 -> v1.15.1 Updating syn v2.0.100 -> v2.0.103 Updating synstructure v0.13.1 -> v0.13.2 Updating tenthash v1.0.0 -> v1.1.0 Updating thread_local v1.1.8 -> v1.1.9 Updating time v0.3.40 -> v0.3.41 Updating time-macros v0.2.21 -> v0.2.22 Updating tinystr v0.7.6 -> v0.8.1 Updating toml v0.8.20 -> v0.8.23 Updating toml_datetime v0.6.8 -> v0.6.11 Updating toml_edit v0.22.24 -> v0.22.27 Adding toml_write v0.1.2 Updating tracing-attributes v0.1.28 -> v0.1.29 Updating tracing-core v0.1.33 -> v0.1.34 Removing utf16_iter v1.0.5 Updating wasi v0.11.0+wasi-snapshot-preview1 -> v0.11.1+wasi-snapshot-preview1 Updating windows v0.61.1 -> v0.61.3 Updating windows-core v0.61.0 -> v0.61.2 Updating windows-future v0.2.0 -> v0.2.1 Updating windows-link v0.1.1 -> v0.1.3 Updating windows-result v0.3.2 -> v0.3.4 Updating windows-strings v0.4.0 -> v0.4.2 Adding windows-sys v0.60.2 Updating windows-targets v0.53.0 -> v0.53.2 Adding windows-threading v0.1.0 Updating winnow v0.7.3 -> v0.7.11 Removing write16 v1.0.0 Updating writeable v0.5.5 -> v0.6.1 Updating yoke v0.7.5 -> v0.8.0 Updating yoke-derive v0.7.5 -> v0.8.0 Adding zerotrie v0.2.2 Updating zerovec v0.10.4 -> v0.11.2 Updating zerovec-derive v0.10.3 -> v0.11.1 --- Cargo.lock | 415 +++++++++++++++++++++++++++-------------------------- 1 file changed, 208 insertions(+), 207 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 01de430925..a7c8ea4a00 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,9 +13,9 @@ dependencies = [ [[package]] name = "adler2" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "allocator-api2" @@ -25,9 +25,9 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "anyhow" -version = "1.0.97" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" [[package]] name = "arbitrary" @@ -100,30 +100,30 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" [[package]] name = "borsh" -version = "1.5.5" +version = "1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5430e3be710b68d984d1391c854eb431a9d548640711faa54eecb1df93db91cc" +checksum = "ad8646f98db542e39fc66e68a20b2144f6a732636df7c2354e74645faaa433ce" dependencies = [ "cfg_aliases", ] [[package]] name = "boxcar" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66bb12751a83493ef4b8da1120451a262554e216a247f14b48cb5e8fe7ed8bdf" +checksum = "26c4925bc979b677330a8c7fe7a8c94af2dbb4a2d37b4a20a80d884400f46baa" [[package]] name = "camino" -version = "1.1.9" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" +checksum = "0da45bc31171d8d6960122e222a67740df867c1dd53b4d51caa297084c185cab" dependencies = [ "serde", ] @@ -153,9 +153,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.16" +version = "1.2.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c" +checksum = "956a5e21988b87f372569b66183b78babf23ebc2e744b733e4350a752c4dafac" dependencies = [ "shlex", ] @@ -178,9 +178,9 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" [[package]] name = "cfg_aliases" @@ -206,7 +206,7 @@ version = "0.102.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72f0a61621a088af69fee8df39ec63cf5b6d0b9ab663a740cdeb376aabf2f244" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "chalk-derive", ] @@ -374,7 +374,7 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -461,9 +461,9 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flate2" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" +checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" dependencies = [ "crc32fast", "miniz_oxide", @@ -471,9 +471,9 @@ dependencies = [ [[package]] name = "foldhash" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" [[package]] name = "form_urlencoded" @@ -501,9 +501,9 @@ checksum = "7ab85b9b05e3978cc9a9cf8fea7f01b494e1a09ed3037e16ba39edc7a29eb61a" [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "libc", @@ -524,9 +524,9 @@ checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" dependencies = [ "allocator-api2", "equivalent", @@ -539,7 +539,7 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" dependencies = [ - "hashbrown 0.15.2", + "hashbrown 0.15.4", ] [[package]] @@ -550,9 +550,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" -version = "0.3.9" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" [[package]] name = "hir" @@ -588,7 +588,7 @@ version = "0.0.0" dependencies = [ "arrayvec", "base-db", - "bitflags 2.9.0", + "bitflags 2.9.1", "cfg", "cov-mark", "drop_bomb", @@ -655,7 +655,7 @@ version = "0.0.0" dependencies = [ "arrayvec", "base-db", - "bitflags 2.9.0", + "bitflags 2.9.1", "chalk-derive", "chalk-ir", "chalk-recursive", @@ -705,21 +705,22 @@ dependencies = [ [[package]] name = "icu_collections" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" dependencies = [ "displaydoc", + "potential_utf", "yoke", "zerofrom", "zerovec", ] [[package]] -name = "icu_locid" -version = "1.5.0" +name = "icu_locale_core" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" dependencies = [ "displaydoc", "litemap", @@ -728,31 +729,11 @@ dependencies = [ "zerovec", ] -[[package]] -name = "icu_locid_transform" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_locid_transform_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_locid_transform_data" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" - [[package]] name = "icu_normalizer" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" dependencies = [ "displaydoc", "icu_collections", @@ -760,67 +741,54 @@ dependencies = [ "icu_properties", "icu_provider", "smallvec", - "utf16_iter", - "utf8_iter", - "write16", "zerovec", ] [[package]] name = "icu_normalizer_data" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" [[package]] name = "icu_properties" -version = "1.5.1" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" dependencies = [ "displaydoc", "icu_collections", - "icu_locid_transform", + "icu_locale_core", "icu_properties_data", "icu_provider", - "tinystr", + "potential_utf", + "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "1.5.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" [[package]] name = "icu_provider" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" dependencies = [ "displaydoc", - "icu_locid", - "icu_provider_macros", + "icu_locale_core", "stable_deref_trait", "tinystr", "writeable", "yoke", "zerofrom", + "zerotrie", "zerovec", ] -[[package]] -name = "icu_provider_macros" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "ide" version = "0.0.0" @@ -898,7 +866,7 @@ version = "0.0.0" dependencies = [ "arrayvec", "base-db", - "bitflags 2.9.0", + "bitflags 2.9.1", "cov-mark", "crossbeam-channel", "either", @@ -976,9 +944,9 @@ dependencies = [ [[package]] name = "idna_adapter" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" dependencies = [ "icu_normalizer", "icu_properties", @@ -991,7 +959,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" dependencies = [ "equivalent", - "hashbrown 0.15.2", + "hashbrown 0.15.4", "serde", ] @@ -1001,7 +969,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f37dccff2791ab604f9babef0ba14fbe0be30bd368dc541e2b08d07c8aa908f3" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "inotify-sys", "libc", ] @@ -1057,9 +1025,9 @@ checksum = "a037eddb7d28de1d0fc42411f501b53b75838d313908078d6698d064f3029b24" [[package]] name = "kqueue" -version = "1.0.8" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7447f1ca1b7b563588a205fe93dea8df60fd981423a768bc1c0ded35ed147d0c" +checksum = "eac30106d7dce88daf4a3fcb4879ea939476d5074a9b7ddd0fb97fa4bed5596a" dependencies = [ "kqueue-sys", "libc", @@ -1099,19 +1067,19 @@ checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" [[package]] name = "libloading" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a793df0d7afeac54f95b471d3af7f0d4fb975699f972341a4b76988d49cdf0c" +checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" dependencies = [ "cfg-if", - "windows-targets 0.53.0", + "windows-targets 0.53.2", ] [[package]] name = "libmimalloc-sys" -version = "0.1.40" +version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07d0e07885d6a754b9c7993f2625187ad694ee985d60f23355ff0e7077261502" +checksum = "ec9d6fac27761dabcd4ee73571cdb06b7022dc99089acbe5435691edffaac0f4" dependencies = [ "cc", "libc", @@ -1123,7 +1091,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "libc", "redox_syscall", ] @@ -1149,9 +1117,9 @@ dependencies = [ [[package]] name = "litemap" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" [[package]] name = "load-cargo" @@ -1174,9 +1142,9 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" dependencies = [ "autocfg", "scopeguard", @@ -1184,9 +1152,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.26" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "lsp-server" @@ -1249,9 +1217,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" [[package]] name = "memmap2" @@ -1273,32 +1241,32 @@ dependencies = [ [[package]] name = "mimalloc" -version = "0.1.44" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99585191385958383e13f6b822e6b6d8d9cf928e7d286ceb092da92b43c87bc1" +checksum = "995942f432bbb4822a7e9c3faa87a695185b0d09273ba85f097b54f4e458f2af" dependencies = [ "libmimalloc-sys", ] [[package]] name = "miniz_oxide" -version = "0.8.5" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", ] [[package]] name = "mio" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" dependencies = [ "libc", "log", "wasi", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1316,7 +1284,7 @@ version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "cfg-if", "cfg_aliases", "libc", @@ -1334,7 +1302,7 @@ version = "8.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2fee8403b3d66ac7b26aee6e40a897d85dc5ce26f44da36b8b73e987cc52e943" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "filetime", "fsevent-sys", "inotify", @@ -1370,9 +1338,9 @@ checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" [[package]] name = "num_cpus" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" dependencies = [ "hermit-abi", "libc", @@ -1398,9 +1366,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.21.1" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "oorandom" @@ -1416,9 +1384,9 @@ checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] name = "parking_lot" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" dependencies = [ "lock_api", "parking_lot_core", @@ -1426,9 +1394,9 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.10" +version = "0.9.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" dependencies = [ "cfg-if", "libc", @@ -1506,9 +1474,18 @@ checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "portable-atomic" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" +checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" + +[[package]] +name = "potential_utf" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +dependencies = [ + "zerovec", +] [[package]] name = "powerfmt" @@ -1569,9 +1546,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.94" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] @@ -1650,7 +1627,7 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "memchr", "unicase", ] @@ -1691,7 +1668,7 @@ version = "0.113.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c33b8fa229789975647ca5426be432c7c327ebde89ab15889928185dbcee3230" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "ra-ap-rustc_hashes", "ra-ap-rustc_index", "tracing", @@ -1783,11 +1760,11 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.10" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1" +checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", ] [[package]] @@ -1881,9 +1858,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.24" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" [[package]] name = "rustc-hash" @@ -1911,11 +1888,11 @@ checksum = "781442f29170c5c93b7185ad559492601acdc71d5bb0706f5868094f45cfcd08" [[package]] name = "rustc_apfloat" -version = "0.2.2+llvm-462a31f5a5ab" +version = "0.2.3+llvm-462a31f5a5ab" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "121e2195ff969977a4e2b5c9965ea867fce7e4cb5aee5b09dee698a7932d574f" +checksum = "486c2179b4796f65bfe2ee33679acf0927ac83ecf583ad6c91c3b4570911b9ad" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "smallvec", ] @@ -1934,7 +1911,7 @@ dependencies = [ "boxcar", "crossbeam-queue", "dashmap", - "hashbrown 0.15.2", + "hashbrown 0.15.4", "hashlink", "indexmap", "parking_lot", @@ -2052,9 +2029,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" dependencies = [ "serde", ] @@ -2076,9 +2053,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "smallvec" -version = "1.14.0" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "smol_str" @@ -2127,9 +2104,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.100" +version = "2.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +checksum = "e4307e30089d6fd6aff212f2da3a1f9e32f3223b1f010fb09b7c95f90f3ca1e8" dependencies = [ "proc-macro2", "quote", @@ -2138,9 +2115,9 @@ dependencies = [ [[package]] name = "synstructure" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", @@ -2183,9 +2160,9 @@ dependencies = [ [[package]] name = "tenthash" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d092d622df8bb64e5de8dc86a3667702d5f1e0fe2f0604c6035540703c8cd1e" +checksum = "e5c4bcc0a4fa333239f43662d15fbf995f384b2aeaf89c4ab4c83353d6cbb952" [[package]] name = "test-fixture" @@ -2270,12 +2247,11 @@ dependencies = [ [[package]] name = "thread_local" -version = "1.1.8" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" dependencies = [ "cfg-if", - "once_cell", ] [[package]] @@ -2311,9 +2287,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.40" +version = "0.3.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d9c75b47bdff86fa3334a3db91356b8d7d86a9b839dab7d0bdc5c3d3a077618" +checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" dependencies = [ "deranged", "itoa", @@ -2334,9 +2310,9 @@ checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" [[package]] name = "time-macros" -version = "0.2.21" +version = "0.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29aa485584182073ed57fd5004aa09c371f021325014694e432313345865fd04" +checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" dependencies = [ "num-conv", "time-core", @@ -2344,9 +2320,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.7.6" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" dependencies = [ "displaydoc", "zerovec", @@ -2354,9 +2330,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.20" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ "serde", "serde_spanned", @@ -2366,26 +2342,33 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.8" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.22.24" +version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ "indexmap", "serde", "serde_spanned", "toml_datetime", + "toml_write", "winnow", ] +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + [[package]] name = "toolchain" version = "0.0.0" @@ -2407,9 +2390,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.28" +version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +checksum = "1b1ffbcf9c6f6b99d386e7444eb608ba646ae452a36b39737deb9663b610f662" dependencies = [ "proc-macro2", "quote", @@ -2418,9 +2401,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.33" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" dependencies = [ "once_cell", "valuable", @@ -2527,12 +2510,6 @@ dependencies = [ "serde", ] -[[package]] -name = "utf16_iter" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" - [[package]] name = "utf8_iter" version = "1.0.4" @@ -2586,9 +2563,9 @@ dependencies = [ [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "winapi-util" @@ -2601,9 +2578,9 @@ dependencies = [ [[package]] name = "windows" -version = "0.61.1" +version = "0.61.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5ee8f3d025738cb02bad7868bbb5f8a6327501e870bf51f1b455b0a2454a419" +checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" dependencies = [ "windows-collections", "windows-core", @@ -2623,9 +2600,9 @@ dependencies = [ [[package]] name = "windows-core" -version = "0.61.0" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" dependencies = [ "windows-implement", "windows-interface", @@ -2636,12 +2613,13 @@ dependencies = [ [[package]] name = "windows-future" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a1d6bbefcb7b60acd19828e1bc965da6fcf18a7e39490c5f8be71e54a19ba32" +checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" dependencies = [ "windows-core", "windows-link", + "windows-threading", ] [[package]] @@ -2668,9 +2646,9 @@ dependencies = [ [[package]] name = "windows-link" -version = "0.1.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" [[package]] name = "windows-numerics" @@ -2684,18 +2662,18 @@ dependencies = [ [[package]] name = "windows-result" -version = "0.3.2" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" dependencies = [ "windows-link", ] [[package]] name = "windows-strings" -version = "0.4.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" dependencies = [ "windows-link", ] @@ -2727,6 +2705,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.2", +] + [[package]] name = "windows-targets" version = "0.48.5" @@ -2760,9 +2747,9 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.53.0" +version = "0.53.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" +checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef" dependencies = [ "windows_aarch64_gnullvm 0.53.0", "windows_aarch64_msvc 0.53.0", @@ -2774,6 +2761,15 @@ dependencies = [ "windows_x86_64_msvc 0.53.0", ] +[[package]] +name = "windows-threading" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" +dependencies = [ + "windows-link", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -2914,9 +2910,9 @@ checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" [[package]] name = "winnow" -version = "0.7.3" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7f4ea97f6f78012141bcdb6a216b2609f0979ada50b20ca5b52dde2eac2bb1" +checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd" dependencies = [ "memchr", ] @@ -2927,17 +2923,11 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23f6174b2566cc4a74f95e1367ec343e7fa80c93cc8087f5c4a3d6a1088b2118" -[[package]] -name = "write16" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" - [[package]] name = "writeable" -version = "0.5.5" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" [[package]] name = "xflags" @@ -2992,9 +2982,9 @@ dependencies = [ [[package]] name = "yoke" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" dependencies = [ "serde", "stable_deref_trait", @@ -3004,9 +2994,9 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" dependencies = [ "proc-macro2", "quote", @@ -3036,10 +3026,21 @@ dependencies = [ ] [[package]] -name = "zerovec" -version = "0.10.4" +name = "zerotrie" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" dependencies = [ "yoke", "zerofrom", @@ -3048,9 +3049,9 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.10.3" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" dependencies = [ "proc-macro2", "quote", From 23712aea069d7ac79132040918e95148b9a25d74 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 13 Jun 2025 10:08:20 +0200 Subject: [PATCH 34/56] `cargo upgrade` --- Cargo.lock | 161 ++++++++++++++---- Cargo.toml | 42 ++--- crates/hir-def/Cargo.toml | 2 +- crates/hir-def/src/lang_item.rs | 1 + crates/hir-ty/Cargo.toml | 2 +- crates/hir-ty/src/chalk_db.rs | 14 +- crates/ide-db/Cargo.toml | 2 +- crates/ide/Cargo.toml | 2 +- crates/intern/src/symbol/symbols.rs | 1 + .../proc-macro-srv/proc-macro-test/Cargo.toml | 2 +- crates/profile/Cargo.toml | 4 +- crates/project-model/src/cargo_workspace.rs | 8 +- crates/project-model/src/sysroot.rs | 2 +- crates/rust-analyzer/Cargo.toml | 14 +- crates/stdx/Cargo.toml | 4 +- crates/syntax/Cargo.toml | 2 +- lib/lsp-server/Cargo.toml | 4 +- lib/lsp-server/src/msg.rs | 4 +- lib/lsp-server/src/stdio.rs | 2 +- xtask/Cargo.toml | 6 +- 20 files changed, 190 insertions(+), 89 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a7c8ea4a00..c2b4e21483 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -60,7 +60,7 @@ dependencies = [ "cfg-if", "libc", "miniz_oxide", - "object", + "object 0.36.7", "rustc-demangle", "windows-targets 0.52.6", ] @@ -130,21 +130,38 @@ dependencies = [ [[package]] name = "cargo-platform" -version = "0.1.9" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" +checksum = "84982c6c0ae343635a3a4ee6dedef965513735c8b183caa7289fa6e27399ebd4" dependencies = [ "serde", ] [[package]] -name = "cargo_metadata" -version = "0.19.2" +name = "cargo-util-schemas" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba" +checksum = "e63d2780ac94487eb9f1fea7b0d56300abc9eb488800854ca217f102f5caccca" +dependencies = [ + "semver", + "serde", + "serde-untagged", + "serde-value", + "thiserror 1.0.69", + "toml", + "unicode-xid", + "url", +] + +[[package]] +name = "cargo_metadata" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f7835cfc6135093070e95eb2b53e5d9b5c403dc3a6be6040ee026270aa82502" dependencies = [ "camino", "cargo-platform", + "cargo-util-schemas", "semver", "serde", "serde_json", @@ -190,9 +207,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chalk-derive" -version = "0.102.0" +version = "0.103.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "feb14e3ff0ebac26d8e58b6ed1417afb60c4a0a44b6425546ee7eb9c75ebb336" +checksum = "eb4899682de915ca7c0b025bdd0a3d34c75fe12184122fda6805a7baddaa293c" dependencies = [ "proc-macro2", "quote", @@ -202,9 +219,9 @@ dependencies = [ [[package]] name = "chalk-ir" -version = "0.102.0" +version = "0.103.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72f0a61621a088af69fee8df39ec63cf5b6d0b9ab663a740cdeb376aabf2f244" +checksum = "90a37d2ab99352b4caca135061e7b4ac67024b648c28ed0b787feec4bea4caed" dependencies = [ "bitflags 2.9.1", "chalk-derive", @@ -212,9 +229,9 @@ dependencies = [ [[package]] name = "chalk-recursive" -version = "0.102.0" +version = "0.103.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbd3415cc540015533aa4a8ad007696d585dd9c5f81e7c099872f1dd4bf14894" +checksum = "c855be60e646664bc37c2496d3dc81ca5ef60520930e5e0f0057a0575aff6c19" dependencies = [ "chalk-derive", "chalk-ir", @@ -225,9 +242,9 @@ dependencies = [ [[package]] name = "chalk-solve" -version = "0.102.0" +version = "0.103.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "747707b0c082b3ecf4b1ae28d0d8df708a46cddd22a386f9cc85a312a4de25ff" +checksum = "477ac6cdfd2013e9f93b09b036c2b607a67b2e728f4777b8422d55a79e9e3a34" dependencies = [ "chalk-derive", "chalk-ir", @@ -431,6 +448,16 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +[[package]] +name = "erased-serde" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e004d887f51fcb9fef17317a2f3525c887d8aa3f4f50fed920816a688284a5b7" +dependencies = [ + "serde", + "typeid", +] + [[package]] name = "expect-test" version = "1.5.1" @@ -1336,6 +1363,15 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + [[package]] name = "num_cpus" version = "1.17.0" @@ -1364,6 +1400,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "object" +version = "0.37.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03fd943161069e1768b4b3d050890ba48730e590f57e56d4aa04e7e090e61b4a" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" version = "1.21.3" @@ -1382,6 +1427,15 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" +[[package]] +name = "ordered-float" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" +dependencies = [ + "num-traits", +] + [[package]] name = "parking_lot" version = "0.12.4" @@ -1413,7 +1467,7 @@ dependencies = [ "edition", "expect-test", "ra-ap-rustc_lexer", - "rustc-literal-escaper", + "rustc-literal-escaper 0.0.3", "stdx", "tracing", ] @@ -1519,7 +1573,7 @@ dependencies = [ "libc", "libloading", "memmap2", - "object", + "object 0.37.1", "paths", "proc-macro-test", "ra-ap-rustc_lexer", @@ -1573,7 +1627,7 @@ dependencies = [ "libc", "perf-event", "tikv-jemalloc-ctl", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -1664,9 +1718,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_abi" -version = "0.113.0" +version = "0.116.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c33b8fa229789975647ca5426be432c7c327ebde89ab15889928185dbcee3230" +checksum = "a967e3a9cd3e38b543f503978e0eccee461e3aea3f7b10e944959bff41dbe612" dependencies = [ "bitflags 2.9.1", "ra-ap-rustc_hashes", @@ -1676,18 +1730,18 @@ dependencies = [ [[package]] name = "ra-ap-rustc_hashes" -version = "0.113.0" +version = "0.116.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d68a3e389927002f552938a90b04787f6435f55b46fc5691360470d1cb2e99d" +checksum = "1ea4c755ecbbffa5743c251344f484ebe571ec7bc5b36d80b2a8ae775d1a7a40" dependencies = [ "rustc-stable-hash", ] [[package]] name = "ra-ap-rustc_index" -version = "0.113.0" +version = "0.116.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32502273df2838d0ca13f1c67e2a48feef940e591f9771869f07e2db2acede53" +checksum = "aca7ad7cf911538c619caa2162339fe98637e9e46f11bb0484ef96735df4d64a" dependencies = [ "ra-ap-rustc_index_macros", "smallvec", @@ -1695,9 +1749,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_index_macros" -version = "0.113.0" +version = "0.116.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a32f081864ae34c7ae6634edfa7a95ab9260ba85015e8b1d347580eda79d14f" +checksum = "8767ba551c9355bc3031be072cc4bb0381106e5e7cd275e72b7a8c76051c4070" dependencies = [ "proc-macro2", "quote", @@ -1706,9 +1760,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_lexer" -version = "0.113.0" +version = "0.116.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed34c51974718c5bd90d876d1364d9725159fc8030c2382b9cb837034152ed68" +checksum = "6101374afb267e6c27e4e2eb0b1352e9f3504c1a8f716f619cd39244e2ed92ab" dependencies = [ "memchr", "unicode-properties", @@ -1717,19 +1771,19 @@ dependencies = [ [[package]] name = "ra-ap-rustc_parse_format" -version = "0.113.0" +version = "0.116.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff0440e5d27facbf4ff13ea651e48c2f6e360b3dbfc56251b41d60719b965fb8" +checksum = "ecd88a19f00da4f43e6727d5013444cbc399804b5046dfa2bbcd28ebed3970ce" dependencies = [ "ra-ap-rustc_lexer", - "rustc-literal-escaper", + "rustc-literal-escaper 0.0.2", ] [[package]] name = "ra-ap-rustc_pattern_analysis" -version = "0.113.0" +version = "0.116.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6056efa57aba3aa0cc69a0bf1a8281624c23ad25b05748d11ebcd4668037bfc" +checksum = "bb332dd32d7850a799862533b1c021e6062558861a4ad57817bf522499fbb892" dependencies = [ "ra-ap-rustc_index", "rustc-hash 2.1.1", @@ -1851,7 +1905,7 @@ dependencies = [ "vfs", "vfs-notify", "walkdir", - "windows-sys 0.59.0", + "windows-sys 0.60.2", "xflags", "xshell", ] @@ -1880,6 +1934,12 @@ version = "0.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0041b6238913c41fe704213a4a9329e2f685a156d1781998128b4149c230ad04" +[[package]] +name = "rustc-literal-escaper" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78744cd17f5d01c75b709e49807d1363e02a940ccee2e9e72435843fdb0d076e" + [[package]] name = "rustc-stable-hash" version = "0.1.2" @@ -1992,6 +2052,27 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-untagged" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "299d9c19d7d466db4ab10addd5703e4c615dec2a5a16dbbafe191045e87ee66e" +dependencies = [ + "erased-serde", + "serde", + "typeid", +] + +[[package]] +name = "serde-value" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" +dependencies = [ + "ordered-float", + "serde", +] + [[package]] name = "serde_derive" version = "1.0.219" @@ -2099,7 +2180,7 @@ dependencies = [ "libc", "miow", "tracing", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -2135,7 +2216,7 @@ dependencies = [ "rayon", "rowan", "rustc-hash 2.1.1", - "rustc-literal-escaper", + "rustc-literal-escaper 0.0.3", "rustc_apfloat", "smol_str", "stdx", @@ -2468,6 +2549,12 @@ version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" +[[package]] +name = "typeid" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" + [[package]] name = "ungrammar" version = "1.16.1" @@ -3060,9 +3147,9 @@ dependencies = [ [[package]] name = "zip" -version = "3.0.0" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12598812502ed0105f607f941c386f43d441e00148fce9dec3ca5ffb0bde9308" +checksum = "153a6fff49d264c4babdcfa6b4d534747f520e56e8f0f384f3b808c4b64cc1fd" dependencies = [ "arbitrary", "crc32fast", diff --git a/Cargo.toml b/Cargo.toml index 975fe277b2..c5f061cad7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -87,11 +87,11 @@ vfs-notify = { path = "./crates/vfs-notify", version = "0.0.0" } vfs = { path = "./crates/vfs", version = "0.0.0" } edition = { path = "./crates/edition", version = "0.0.0" } -ra-ap-rustc_lexer = { version = "0.113", default-features = false } -ra-ap-rustc_parse_format = { version = "0.113", default-features = false } -ra-ap-rustc_index = { version = "0.113", default-features = false } -ra-ap-rustc_abi = { version = "0.113", default-features = false } -ra-ap-rustc_pattern_analysis = { version = "0.113", default-features = false } +ra-ap-rustc_lexer = { version = "0.116", default-features = false } +ra-ap-rustc_parse_format = { version = "0.116", default-features = false } +ra-ap-rustc_index = { version = "0.116", default-features = false } +ra-ap-rustc_abi = { version = "0.116", default-features = false } +ra-ap-rustc_pattern_analysis = { version = "0.116", default-features = false } # local crates that aren't published to crates.io. These should not have versions. @@ -101,35 +101,35 @@ la-arena = { version = "0.3.1" } lsp-server = { version = "0.7.8" } # non-local crates -anyhow = "1.0.97" +anyhow = "1.0.98" arrayvec = "0.7.6" -bitflags = "2.9.0" -cargo_metadata = "0.19.2" -camino = "1.1.9" -chalk-solve = { version = "0.102.0", default-features = false } -chalk-ir = "0.102.0" -chalk-recursive = { version = "0.102.0", default-features = false } -chalk-derive = "0.102.0" +bitflags = "2.9.1" +cargo_metadata = "0.20.0" +camino = "1.1.10" +chalk-solve = { version = "0.103.0", default-features = false } +chalk-ir = "0.103.0" +chalk-recursive = { version = "0.103.0", default-features = false } +chalk-derive = "0.103.0" crossbeam-channel = "0.5.15" dissimilar = "1.0.10" dot = "0.1.4" either = "1.15.0" expect-test = "1.5.1" -indexmap = { version = "2.8.0", features = ["serde"] } +indexmap = { version = "2.9.0", features = ["serde"] } itertools = "0.14.0" -libc = "0.2.171" -libloading = "0.8.6" +libc = "0.2.172" +libloading = "0.8.8" memmap2 = "0.9.5" nohash-hasher = "0.2.0" oorandom = "11.1.5" -object = { version = "0.36.7", default-features = false, features = [ +object = { version = "0.37.1", default-features = false, features = [ "std", "read_core", "elf", "macho", "pe", ] } -process-wrap = { version = "8.2.0", features = ["std"] } +process-wrap = { version = "8.2.1", features = ["std"] } pulldown-cmark-to-cmark = "10.0.4" pulldown-cmark = { version = "0.9.6", default-features = false } rayon = "1.10.0" @@ -141,8 +141,8 @@ serde = { version = "1.0.219" } serde_derive = { version = "1.0.219" } serde_json = "1.0.140" rustc-hash = "2.1.1" -rustc-literal-escaper = "0.0.2" -smallvec = { version = "1.14.0", features = [ +rustc-literal-escaper = "0.0.3" +smallvec = { version = "1.15.1", features = [ "const_new", "union", "const_generics", @@ -166,7 +166,7 @@ xshell = "0.2.7" # We need to freeze the version of the crate, as the raw-api feature is considered unstable dashmap = { version = "=6.1.0", features = ["raw-api", "inline"] } # We need to freeze the version of the crate, as it needs to match with dashmap -hashbrown = { version = "0.14.0", features = [ +hashbrown = { version = "0.14.*", features = [ "inline-more", ], default-features = false } diff --git a/crates/hir-def/Cargo.toml b/crates/hir-def/Cargo.toml index c1c89e8d1c..c6922eca49 100644 --- a/crates/hir-def/Cargo.toml +++ b/crates/hir-def/Cargo.toml @@ -25,7 +25,7 @@ rustc-hash.workspace = true tracing.workspace = true smallvec.workspace = true triomphe.workspace = true -rustc_apfloat = "0.2.2" +rustc_apfloat = "0.2.3" text-size.workspace = true salsa.workspace = true salsa-macros.workspace = true diff --git a/crates/hir-def/src/lang_item.rs b/crates/hir-def/src/lang_item.rs index 1614ef0da4..8f071cd953 100644 --- a/crates/hir-def/src/lang_item.rs +++ b/crates/hir-def/src/lang_item.rs @@ -377,6 +377,7 @@ language_item_table! { AsyncFnMut, sym::async_fn_mut, async_fn_mut_trait, Target::Trait, GenericRequirement::Exact(1); AsyncFnOnce, sym::async_fn_once, async_fn_once_trait, Target::Trait, GenericRequirement::Exact(1); + AsyncFnOnceOutput, sym::async_fn_once_output,async_fn_once_output, Target::AssocTy, GenericRequirement::None; FnOnceOutput, sym::fn_once_output, fn_once_output, Target::AssocTy, GenericRequirement::None; Future, sym::future_trait, future_trait, Target::Trait, GenericRequirement::Exact(0); diff --git a/crates/hir-ty/Cargo.toml b/crates/hir-ty/Cargo.toml index efa544cf39..8b65126e7b 100644 --- a/crates/hir-ty/Cargo.toml +++ b/crates/hir-ty/Cargo.toml @@ -31,7 +31,7 @@ la-arena.workspace = true triomphe.workspace = true typed-arena = "2.0.2" indexmap.workspace = true -rustc_apfloat = "0.2.2" +rustc_apfloat = "0.2.3" query-group.workspace = true salsa.workspace = true salsa-macros.workspace = true diff --git a/crates/hir-ty/src/chalk_db.rs b/crates/hir-ty/src/chalk_db.rs index 710ac6e542..f658e23665 100644 --- a/crates/hir-ty/src/chalk_db.rs +++ b/crates/hir-ty/src/chalk_db.rs @@ -261,10 +261,20 @@ impl chalk_solve::RustIrDatabase for ChalkContext<'_> { &self, well_known_trait: WellKnownTrait, ) -> Option> { - let lang_attr = lang_item_from_well_known_trait(well_known_trait); - let trait_ = lang_attr.resolve_trait(self.db, self.krate)?; + let lang_item = lang_item_from_well_known_trait(well_known_trait); + let trait_ = lang_item.resolve_trait(self.db, self.krate)?; Some(to_chalk_trait_id(trait_)) } + fn well_known_assoc_type_id( + &self, + assoc_type: rust_ir::WellKnownAssocType, + ) -> Option> { + let lang_item = match assoc_type { + rust_ir::WellKnownAssocType::AsyncFnOnceOutput => LangItem::AsyncFnOnceOutput, + }; + let alias = lang_item.resolve_type_alias(self.db, self.krate)?; + Some(to_assoc_type_id(alias)) + } fn program_clauses_for_env( &self, diff --git a/crates/ide-db/Cargo.toml b/crates/ide-db/Cargo.toml index 583318de26..acde1d665d 100644 --- a/crates/ide-db/Cargo.toml +++ b/crates/ide-db/Cargo.toml @@ -22,7 +22,7 @@ either.workspace = true itertools.workspace = true arrayvec.workspace = true indexmap.workspace = true -memchr = "2.7.4" +memchr = "2.7.5" salsa.workspace = true salsa-macros.workspace = true query-group.workspace = true diff --git a/crates/ide/Cargo.toml b/crates/ide/Cargo.toml index 1d19daf2f5..2f8ed88fbb 100644 --- a/crates/ide/Cargo.toml +++ b/crates/ide/Cargo.toml @@ -25,7 +25,7 @@ dot.workspace = true smallvec.workspace = true triomphe.workspace = true nohash-hasher.workspace = true -rustc_apfloat = "0.2.2" +rustc_apfloat = "0.2.3" # local deps cfg.workspace = true diff --git a/crates/intern/src/symbol/symbols.rs b/crates/intern/src/symbol/symbols.rs index fc922dd849..d5cbb7328c 100644 --- a/crates/intern/src/symbol/symbols.rs +++ b/crates/intern/src/symbol/symbols.rs @@ -222,6 +222,7 @@ define_symbols! { fn_once_output, fn_once, async_fn_once, + async_fn_once_output, async_fn_mut, async_fn, fn_ptr_addr, diff --git a/crates/proc-macro-srv/proc-macro-test/Cargo.toml b/crates/proc-macro-srv/proc-macro-test/Cargo.toml index eddefb33c0..c416d997a8 100644 --- a/crates/proc-macro-srv/proc-macro-test/Cargo.toml +++ b/crates/proc-macro-srv/proc-macro-test/Cargo.toml @@ -9,4 +9,4 @@ license = "MIT OR Apache-2.0" [lib] [build-dependencies] -cargo_metadata = "0.19.2" +cargo_metadata = "0.20.0" diff --git a/crates/profile/Cargo.toml b/crates/profile/Cargo.toml index 1fb1383272..bae891c198 100644 --- a/crates/profile/Cargo.toml +++ b/crates/profile/Cargo.toml @@ -12,7 +12,7 @@ rust-version.workspace = true [lib] [dependencies] -cfg-if = "1.0.0" +cfg-if = "1.0.1" jemalloc-ctl = { version = "0.5.4", package = "tikv-jemalloc-ctl", optional = true } [target.'cfg(all(target_os = "linux", not(target_env = "ohos")))'.dependencies] @@ -22,7 +22,7 @@ perf-event = "=0.4.7" libc.workspace = true [target.'cfg(windows)'.dependencies] -windows-sys = { version = "0.59", features = [ +windows-sys = { version = "0.60", features = [ "Win32_System_Threading", "Win32_System_ProcessStatus", ] } diff --git a/crates/project-model/src/cargo_workspace.rs b/crates/project-model/src/cargo_workspace.rs index bb02284a51..1fade7b332 100644 --- a/crates/project-model/src/cargo_workspace.rs +++ b/crates/project-model/src/cargo_workspace.rs @@ -492,7 +492,7 @@ impl CargoWorkspace { is_virtual_workspace &= manifest != ws_manifest_path; let pkg = packages.alloc(PackageData { id: id.repr.clone(), - name, + name: name.to_string(), version, manifest: manifest.clone(), targets: Vec::new(), @@ -547,10 +547,12 @@ impl CargoWorkspace { .flat_map(|dep| DepKind::iter(&dep.dep_kinds).map(move |kind| (dep, kind))); for (dep_node, kind) in dependencies { let &pkg = pkg_by_id.get(&dep_node.pkg).unwrap(); - let dep = PackageDependency { name: dep_node.name.clone(), pkg, kind }; + let dep = PackageDependency { name: dep_node.name.to_string(), pkg, kind }; packages[source].dependencies.push(dep); } - packages[source].active_features.extend(node.features); + packages[source] + .active_features + .extend(node.features.into_iter().map(|it| it.to_string())); } CargoWorkspace { diff --git a/crates/project-model/src/sysroot.rs b/crates/project-model/src/sysroot.rs index d4055d9a0a..ebd86e3dc4 100644 --- a/crates/project-model/src/sysroot.rs +++ b/crates/project-model/src/sysroot.rs @@ -339,7 +339,7 @@ impl Sysroot { Some(_) => { tracing::warn!("unknown rustc-std-workspace-* crate: {}", package.name) } - None => match &*package.name { + None => match &**package.name { "core" => real_core = Some(package.id.clone()), "alloc" => real_alloc = Some(package.id.clone()), "std" => real_std = Some(package.id.clone()), diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml index b59d06838e..5e63521d74 100644 --- a/crates/rust-analyzer/Cargo.toml +++ b/crates/rust-analyzer/Cargo.toml @@ -29,7 +29,7 @@ indexmap.workspace = true itertools.workspace = true scip = "0.5.2" lsp-types = { version = "=0.95.0", features = ["proposed"] } -parking_lot = "0.12.3" +parking_lot = "0.12.4" xflags = "0.3.2" oorandom = "11.1.5" rayon.workspace = true @@ -37,19 +37,19 @@ rustc-hash.workspace = true serde_json = { workspace = true, features = ["preserve_order"] } serde.workspace = true serde_derive.workspace = true -tenthash = "1.0.0" -num_cpus = "1.16.0" -mimalloc = { version = "0.1.44", default-features = false, optional = true } +tenthash = "1.1.0" +num_cpus = "1.17.0" +mimalloc = { version = "0.1.46", default-features = false, optional = true } lsp-server.workspace = true tracing.workspace = true tracing-subscriber.workspace = true tracing-tree.workspace = true triomphe.workspace = true -toml = "0.8.20" +toml = "0.8.23" nohash-hasher.workspace = true walkdir = "2.5.0" semver.workspace = true -memchr = "2.7.4" +memchr = "2.7.5" cargo_metadata.workspace = true process-wrap.workspace = true @@ -75,7 +75,7 @@ vfs.workspace = true paths.workspace = true [target.'cfg(windows)'.dependencies] -windows-sys = { version = "0.59", features = [ +windows-sys = { version = "0.60", features = [ "Win32_System_Diagnostics_Debug", "Win32_System_Threading", ] } diff --git a/crates/stdx/Cargo.toml b/crates/stdx/Cargo.toml index b37aded6f6..a6d5781660 100644 --- a/crates/stdx/Cargo.toml +++ b/crates/stdx/Cargo.toml @@ -12,7 +12,7 @@ rust-version.workspace = true [lib] [dependencies] -backtrace = { version = "0.3.74", optional = true } +backtrace = { version = "0.3.75", optional = true } jod-thread = "1.0.0" crossbeam-channel.workspace = true itertools.workspace = true @@ -25,7 +25,7 @@ libc.workspace = true [target.'cfg(windows)'.dependencies] miow = "0.6.0" -windows-sys = { version = "0.59", features = ["Win32_Foundation"] } +windows-sys = { version = "0.60", features = ["Win32_Foundation"] } [features] # Uncomment to enable for the whole crate graph diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml index 4c7704803e..9d3aaa8d4e 100644 --- a/crates/syntax/Cargo.toml +++ b/crates/syntax/Cargo.toml @@ -27,7 +27,7 @@ stdx.workspace = true [dev-dependencies] rayon.workspace = true expect-test = "1.5.1" -rustc_apfloat = "0.2.2" +rustc_apfloat = "0.2.3" test-utils.workspace = true diff --git a/lib/lsp-server/Cargo.toml b/lib/lsp-server/Cargo.toml index 1dc6d3ce5d..35a5a4d82b 100644 --- a/lib/lsp-server/Cargo.toml +++ b/lib/lsp-server/Cargo.toml @@ -7,7 +7,7 @@ repository = "https://github.com/rust-lang/rust-analyzer/tree/master/lib/lsp-ser edition = "2024" [dependencies] -log = "0.4.26" +log = "0.4.27" serde_json = "1.0.140" serde = { version = "1.0.219" } serde_derive = { version = "1.0.219" } @@ -15,7 +15,7 @@ crossbeam-channel.workspace = true [dev-dependencies] lsp-types = "=0.95" -ctrlc = "3.4.5" +ctrlc = "3.4.7" [lints] workspace = true diff --git a/lib/lsp-server/src/msg.rs b/lib/lsp-server/src/msg.rs index 2749557b91..399d674e41 100644 --- a/lib/lsp-server/src/msg.rs +++ b/lib/lsp-server/src/msg.rs @@ -283,12 +283,12 @@ fn read_msg_text(inp: &mut dyn BufRead) -> io::Result> { buf.resize(size, 0); inp.read_exact(&mut buf)?; let buf = String::from_utf8(buf).map_err(invalid_data)?; - log::debug!("< {}", buf); + log::debug!("< {buf}"); Ok(Some(buf)) } fn write_msg_text(out: &mut dyn Write, msg: &str) -> io::Result<()> { - log::debug!("> {}", msg); + log::debug!("> {msg}"); write!(out, "Content-Length: {}\r\n\r\n", msg.len())?; out.write_all(msg.as_bytes())?; out.flush()?; diff --git a/lib/lsp-server/src/stdio.rs b/lib/lsp-server/src/stdio.rs index c558b6c6e7..eccc89fd59 100644 --- a/lib/lsp-server/src/stdio.rs +++ b/lib/lsp-server/src/stdio.rs @@ -38,7 +38,7 @@ pub(crate) fn stdio_transport() -> (Sender, Receiver, IoThread while let Some(msg) = Message::read(&mut stdin)? { let is_exit = matches!(&msg, Message::Notification(n) if n.is_exit()); - debug!("sending message {:#?}", msg); + debug!("sending message {msg:#?}"); if let Err(e) = reader_sender.send(msg) { return Err(io::Error::other(e)); } diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml index bb7d83c4b7..8cd5811c0a 100644 --- a/xtask/Cargo.toml +++ b/xtask/Cargo.toml @@ -9,14 +9,14 @@ rust-version.workspace = true [dependencies] anyhow.workspace = true directories = "6.0" -flate2 = "1.1.0" +flate2 = "1.1.2" write-json = "0.1.4" xshell.workspace = true xflags = "0.3.2" time = { version = "0.3", default-features = false } -zip = { version = "3.0", default-features = false, features = ["deflate-flate2", "time"] } +zip = { version = "4.0", default-features = false, features = ["deflate-flate2", "time"] } stdx.workspace = true -proc-macro2 = "1.0.94" +proc-macro2 = "1.0.95" quote = "1.0.40" ungrammar = "1.16.1" either.workspace = true From 16ebd2990f64978789955613785ad2301dba7fc3 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 13 Jun 2025 09:05:50 +0200 Subject: [PATCH 35/56] Remove unnecessary item tree query calls --- crates/hir-def/src/nameres/collector.rs | 96 ++++++++++++------------- 1 file changed, 47 insertions(+), 49 deletions(-) diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index 185cc0596b..29f94ac2dc 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -36,7 +36,7 @@ use crate::{ item_scope::{GlobId, ImportId, ImportOrExternCrate, PerNsGlobImports}, item_tree::{ self, FieldsShape, ImportAlias, ImportKind, ItemTree, ItemTreeAstId, Macro2, MacroCall, - MacroRules, Mod, ModItemId, ModKind, TreeId, UseTreeKind, + MacroRules, Mod, ModItemId, ModKind, TreeId, }, macro_call_as_call_id, nameres::{ @@ -140,8 +140,6 @@ struct ImportSource { id: UseId, is_prelude: bool, kind: ImportKind, - tree: TreeId, - item: FileAstId, } #[derive(Debug, Eq, PartialEq)] @@ -155,7 +153,6 @@ struct Import { impl Import { fn from_use( tree: &ItemTree, - tree_id: TreeId, item: FileAstId, id: UseId, is_prelude: bool, @@ -168,7 +165,7 @@ impl Import { path, alias, visibility: visibility.clone(), - source: ImportSource { use_tree: idx, id, is_prelude, kind, tree: tree_id, item }, + source: ImportSource { use_tree: idx, id, is_prelude, kind }, }); }); } @@ -183,15 +180,15 @@ struct ImportDirective { } #[derive(Clone, Debug, Eq, PartialEq)] -struct MacroDirective { +struct MacroDirective<'db> { module_id: LocalModuleId, depth: usize, - kind: MacroDirectiveKind, + kind: MacroDirectiveKind<'db>, container: ItemContainerId, } #[derive(Clone, Debug, Eq, PartialEq)] -enum MacroDirectiveKind { +enum MacroDirectiveKind<'db> { FnLike { ast_id: AstIdWithPath, expand_to: ExpandTo, @@ -210,28 +207,29 @@ enum MacroDirectiveKind { attr: Attr, mod_item: ModItemId, /* is this needed? */ tree: TreeId, + item_tree: &'db ItemTree, }, } /// Walks the tree of module recursively -struct DefCollector<'a> { - db: &'a dyn DefDatabase, +struct DefCollector<'db> { + db: &'db dyn DefDatabase, def_map: DefMap, local_def_map: LocalDefMap, /// Set only in case of blocks. - crate_local_def_map: Option<&'a LocalDefMap>, + crate_local_def_map: Option<&'db LocalDefMap>, // The dependencies of the current crate, including optional deps like `test`. deps: FxHashMap, glob_imports: FxHashMap>, unresolved_imports: Vec, indeterminate_imports: Vec<(ImportDirective, PerNs)>, - unresolved_macros: Vec, + unresolved_macros: Vec>, // We'd like to avoid emitting a diagnostics avalanche when some `extern crate` doesn't // resolve. When we emit diagnostics for unresolved imports, we only do so if the import // doesn't start with an unresolved crate's name. unresolved_extern_crates: FxHashSet, mod_dirs: FxHashMap, - cfg_options: &'a CfgOptions, + cfg_options: &'db CfgOptions, /// List of procedural macros defined by this crate. This is read from the dynamic library /// built by the build system, and is the list of proc-macros we can actually expand. It is /// empty when proc-macro support is disabled (in which case we still do name resolution for @@ -249,7 +247,7 @@ struct DefCollector<'a> { skip_attrs: FxHashMap>, AttrId>, } -impl DefCollector<'_> { +impl<'db> DefCollector<'db> { fn seed_with_top_level(&mut self) { let _p = tracing::info_span!("seed_with_top_level").entered(); @@ -461,7 +459,7 @@ impl DefCollector<'_> { self.unresolved_macros.iter().enumerate().find_map(|(idx, directive)| match &directive .kind { - MacroDirectiveKind::Attr { ast_id, mod_item, attr, tree } => { + MacroDirectiveKind::Attr { ast_id, mod_item, attr, tree, item_tree } => { self.def_map.diagnostics.push(DefDiagnostic::unresolved_macro_call( directive.module_id, MacroCallKind::Attr { @@ -474,14 +472,20 @@ impl DefCollector<'_> { self.skip_attrs.insert(ast_id.ast_id.with_value(mod_item.ast_id()), attr.id); - Some((idx, directive, *mod_item, *tree)) + Some((idx, directive, *mod_item, *tree, *item_tree)) } _ => None, }); match unresolved_attr { - Some((pos, &MacroDirective { module_id, depth, container, .. }, mod_item, tree_id)) => { - let item_tree = &tree_id.item_tree(self.db); + Some(( + pos, + &MacroDirective { module_id, depth, container, .. }, + mod_item, + tree_id, + item_tree, + )) => { + // FIXME: Remove this clone let mod_dir = self.mod_dirs[&module_id].clone(); ModCollector { def_collector: self, @@ -862,8 +866,6 @@ impl DefCollector<'_> { kind: kind @ (ImportKind::Plain | ImportKind::TypeOnly), id, use_tree, - tree, - item, .. } => { let name = match &import.alias { @@ -896,13 +898,11 @@ impl DefCollector<'_> { let Some(ImportOrExternCrate::ExternCrate(_)) = def.import else { return false; }; - let item_tree = tree.item_tree(self.db); - let use_kind = item_tree[item].use_tree.kind(); - let UseTreeKind::Single { path, .. } = use_kind else { + if kind == ImportKind::Glob { return false; - }; - matches!(path.kind, PathKind::Plain | PathKind::SELF) - && path.segments().len() < 2 + } + matches!(import.path.kind, PathKind::Plain | PathKind::SELF) + && import.path.segments().len() < 2 }; if is_extern_crate_reimport_without_prefix() { def.vis = vis; @@ -1256,7 +1256,7 @@ impl DefCollector<'_> { fn resolve_macros(&mut self) -> ReachedFixedPoint { let mut macros = mem::take(&mut self.unresolved_macros); let mut resolved = Vec::new(); - let mut push_resolved = |directive: &MacroDirective, call_id| { + let mut push_resolved = |directive: &MacroDirective<'_>, call_id| { resolved.push((directive.module_id, directive.depth, directive.container, call_id)); }; @@ -1269,7 +1269,7 @@ impl DefCollector<'_> { let mut eager_callback_buffer = vec![]; let mut res = ReachedFixedPoint::Yes; // Retain unresolved macros after this round of resolution. - let mut retain = |directive: &MacroDirective| { + let mut retain = |directive: &MacroDirective<'db>| { let subns = match &directive.kind { MacroDirectiveKind::FnLike { .. } => MacroSubNs::Bang, MacroDirectiveKind::Attr { .. } | MacroDirectiveKind::Derive { .. } => { @@ -1364,7 +1364,13 @@ impl DefCollector<'_> { return Resolved::Yes; } } - MacroDirectiveKind::Attr { ast_id: file_ast_id, mod_item, attr, tree } => { + MacroDirectiveKind::Attr { + ast_id: file_ast_id, + mod_item, + attr, + tree, + item_tree, + } => { let &AstIdWithPath { ast_id, ref path } = file_ast_id; let file_id = ast_id.file_id; @@ -1375,7 +1381,6 @@ impl DefCollector<'_> { .skip_attrs .insert(InFile::new(file_id, mod_item.ast_id()), attr.id); - let item_tree = tree.item_tree(self.db); ModCollector { def_collector: collector, macro_depth: directive.depth, @@ -1646,8 +1651,7 @@ impl DefCollector<'_> { import: Import { ref path, - source: - ImportSource { use_tree, id, is_prelude: _, kind: _, tree: _, item: _ }, + source: ImportSource { use_tree, id, is_prelude: _, kind: _ }, .. }, .. @@ -1671,12 +1675,12 @@ impl DefCollector<'_> { } /// Walks a single module, populating defs, imports and macros -struct ModCollector<'a, 'b> { - def_collector: &'a mut DefCollector<'b>, +struct ModCollector<'a, 'db> { + def_collector: &'a mut DefCollector<'db>, macro_depth: usize, module_id: LocalModuleId, tree_id: TreeId, - item_tree: &'a ItemTree, + item_tree: &'db ItemTree, mod_dir: ModDir, } @@ -1753,20 +1757,13 @@ impl ModCollector<'_, '_> { UseLoc { container: module, id: InFile::new(self.file_id(), item_tree_id) } .intern(db); let is_prelude = attrs.by_key(sym::prelude_import).exists(); - Import::from_use( - self.item_tree, - self.tree_id, - item_tree_id, - id, - is_prelude, - |import| { - self.def_collector.unresolved_imports.push(ImportDirective { - module_id: self.module_id, - import, - status: PartialResolvedImport::Unresolved, - }); - }, - ) + Import::from_use(self.item_tree, item_tree_id, id, is_prelude, |import| { + self.def_collector.unresolved_imports.push(ImportDirective { + module_id: self.module_id, + import, + status: PartialResolvedImport::Unresolved, + }); + }) } ModItemId::ExternCrate(item_tree_id) => { let item_tree::ExternCrate { name, visibility, alias } = @@ -2268,6 +2265,7 @@ impl ModCollector<'_, '_> { attr: attr.clone(), mod_item, tree: self.tree_id, + item_tree: self.item_tree, }, container, }); From d78cade65e8ac157e1f7825f8bc1e6aaf376ab98 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 12 Jun 2025 13:10:15 +0200 Subject: [PATCH 36/56] Generate annotations for macro defined items if their name is in the input --- crates/ide/src/annotations.rs | 82 ++++++++++++++++++++++++++--- crates/ide/src/navigation_target.rs | 2 +- 2 files changed, 76 insertions(+), 8 deletions(-) diff --git a/crates/ide/src/annotations.rs b/crates/ide/src/annotations.rs index 3d71da985b..05196ac98c 100644 --- a/crates/ide/src/annotations.rs +++ b/crates/ide/src/annotations.rs @@ -10,6 +10,7 @@ use crate::{ NavigationTarget, RunnableKind, annotations::fn_references::find_all_methods, goto_implementation::goto_implementation, + navigation_target, references::find_all_refs, runnables::{Runnable, runnables}, }; @@ -148,15 +149,32 @@ pub(crate) fn annotations( node: InFile, source_file_id: FileId, ) -> Option<(TextRange, Option)> { - if let Some(InRealFile { file_id, value }) = node.original_ast_node_rooted(db) { - if file_id.file_id(db) == source_file_id { - return Some(( - value.syntax().text_range(), - value.name().map(|name| name.syntax().text_range()), - )); + if let Some(name) = node.value.name().map(|name| name.syntax().text_range()) { + // if we have a name, try mapping that out of the macro expansion as we can put the + // annotation on that name token + // See `test_no_annotations_macro_struct_def` vs `test_annotations_macro_struct_def_call_site` + let res = navigation_target::orig_range_with_focus_r( + db, + node.file_id, + node.value.syntax().text_range(), + Some(name), + ); + if res.call_site.0.file_id == source_file_id { + if let Some(name_range) = res.call_site.1 { + return Some((res.call_site.0.range, Some(name_range))); + } } + }; + // otherwise try upmapping the entire node out of attributes + let InRealFile { file_id, value } = node.original_ast_node_rooted(db)?; + if file_id.file_id(db) == source_file_id { + Some(( + value.syntax().text_range(), + value.name().map(|name| name.syntax().text_range()), + )) + } else { + None } - None } }); @@ -913,6 +931,56 @@ m!(); ); } + #[test] + fn test_annotations_macro_struct_def_call_site() { + check( + r#" +//- /lib.rs +macro_rules! m { + ($name:ident) => { + struct $name {} + }; +} + +m! { + Name +}; +"#, + expect![[r#" + [ + Annotation { + range: 83..87, + kind: HasImpls { + pos: FilePositionWrapper { + file_id: FileId( + 0, + ), + offset: 83, + }, + data: Some( + [], + ), + }, + }, + Annotation { + range: 83..87, + kind: HasReferences { + pos: FilePositionWrapper { + file_id: FileId( + 0, + ), + offset: 83, + }, + data: Some( + [], + ), + }, + }, + ] + "#]], + ); + } + #[test] fn test_annotations_appear_above_whole_item_when_configured_to_do_so() { check_with_config( diff --git a/crates/ide/src/navigation_target.rs b/crates/ide/src/navigation_target.rs index 9334b73fc7..4c7c597e68 100644 --- a/crates/ide/src/navigation_target.rs +++ b/crates/ide/src/navigation_target.rs @@ -867,7 +867,7 @@ pub(crate) fn orig_range_with_focus_r( } // def site name - // FIXME: This can be de improved + // FIXME: This can be improved Some((focus_range, _ctxt)) => { match value_range { // but overall node is in macro input From b9ce647cf170f16d39c5f1111df6cb4dd7f3a652 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 13 Jun 2025 14:42:23 +0200 Subject: [PATCH 37/56] Bring back EMPTY item tree deduplication --- crates/hir-def/src/item_tree.rs | 49 +++++++++++++++++++-------- crates/hir-def/src/item_tree/lower.rs | 4 +-- 2 files changed, 37 insertions(+), 16 deletions(-) diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs index bf482d33e7..f61b403b84 100644 --- a/crates/hir-def/src/item_tree.rs +++ b/crates/hir-def/src/item_tree.rs @@ -86,9 +86,10 @@ impl fmt::Debug for RawVisibilityId { } } -#[salsa_macros::tracked(returns(ref))] -pub(crate) fn file_item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> ItemTree { +#[salsa_macros::tracked(returns(deref))] +pub(crate) fn file_item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc { let _p = tracing::info_span!("file_item_tree_query", ?file_id).entered(); + static EMPTY: OnceLock> = OnceLock::new(); let ctx = lower::Ctx::new(db, file_id); let syntax = db.parse_or_expand(file_id); @@ -116,16 +117,35 @@ pub(crate) fn file_item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> }, } }; - - item_tree.shrink_to_fit(); - item_tree + let ItemTree { top_level, top_attrs, attrs, vis, big_data, small_data } = &item_tree; + if small_data.is_empty() + && big_data.is_empty() + && top_level.is_empty() + && attrs.is_empty() + && top_attrs.is_empty() + && vis.arena.is_empty() + { + EMPTY + .get_or_init(|| { + Arc::new(ItemTree { + top_level: Box::new([]), + attrs: FxHashMap::default(), + small_data: FxHashMap::default(), + big_data: FxHashMap::default(), + top_attrs: RawAttrs::EMPTY, + vis: ItemVisibilities { arena: ThinVec::new() }, + }) + }) + .clone() + } else { + item_tree.shrink_to_fit(); + Arc::new(item_tree) + } } -#[salsa_macros::tracked(returns(ref))] +#[salsa_macros::tracked(returns(deref))] pub(crate) fn block_item_tree_query(db: &dyn DefDatabase, block: BlockId) -> Arc { let _p = tracing::info_span!("block_item_tree_query", ?block).entered(); - // Blocks have a tendency to be empty due to macro calls that do not expand to items, - // so deduplicate this case via `Arc` to reduce the size of the query storage here. static EMPTY: OnceLock> = OnceLock::new(); let loc = block.lookup(db); @@ -133,11 +153,13 @@ pub(crate) fn block_item_tree_query(db: &dyn DefDatabase, block: BlockId) -> Arc let ctx = lower::Ctx::new(db, loc.ast_id.file_id); let mut item_tree = ctx.lower_block(&block); - if item_tree.small_data.is_empty() - && item_tree.big_data.is_empty() - && item_tree.top_level.is_empty() - && item_tree.attrs.is_empty() - && item_tree.top_attrs.is_empty() + let ItemTree { top_level, top_attrs, attrs, vis, big_data, small_data } = &item_tree; + if small_data.is_empty() + && big_data.is_empty() + && top_level.is_empty() + && attrs.is_empty() + && top_attrs.is_empty() + && vis.arena.is_empty() { EMPTY .get_or_init(|| { @@ -163,7 +185,6 @@ pub struct ItemTree { top_attrs: RawAttrs, attrs: FxHashMap, RawAttrs>, vis: ItemVisibilities, - // FIXME: They values store the key, turn this into a FxHashSet instead? big_data: FxHashMap, BigModItem>, small_data: FxHashMap, SmallModItem>, } diff --git a/crates/hir-def/src/item_tree/lower.rs b/crates/hir-def/src/item_tree/lower.rs index fe1b8e3134..f327366715 100644 --- a/crates/hir-def/src/item_tree/lower.rs +++ b/crates/hir-def/src/item_tree/lower.rs @@ -383,8 +383,8 @@ impl<'a> Ctx<'a> { }); match &vis { RawVisibility::Public => RawVisibilityId::PUB, - RawVisibility::Module(path, explicitiy) if path.segments().is_empty() => { - match (path.kind, explicitiy) { + RawVisibility::Module(path, explicitness) if path.segments().is_empty() => { + match (path.kind, explicitness) { (PathKind::SELF, VisibilityExplicitness::Explicit) => { RawVisibilityId::PRIV_EXPLICIT } From 9f051ee104a5e895ae15bbcd81ae32bd6f161996 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 13 Jun 2025 15:34:03 +0200 Subject: [PATCH 38/56] Use `ThinVec` in `ItemScope` in a couple places --- crates/hir-def/src/item_scope.rs | 36 +++++++++++++++----------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/crates/hir-def/src/item_scope.rs b/crates/hir-def/src/item_scope.rs index 5362c0588d..8591874eb9 100644 --- a/crates/hir-def/src/item_scope.rs +++ b/crates/hir-def/src/item_scope.rs @@ -13,6 +13,7 @@ use smallvec::{SmallVec, smallvec}; use span::Edition; use stdx::format_to; use syntax::ast; +use thin_vec::ThinVec; use crate::{ AdtId, BuiltinType, ConstId, ExternBlockId, ExternCrateId, FxIndexMap, HasModule, ImplId, @@ -155,22 +156,21 @@ pub struct ItemScope { /// The defs declared in this scope. Each def has a single scope where it is /// declared. - declarations: Vec, + declarations: ThinVec, - impls: Vec, - #[allow(clippy::box_collection)] - extern_blocks: Option>>, - unnamed_consts: Vec, + impls: ThinVec, + extern_blocks: ThinVec, + unnamed_consts: ThinVec, /// Traits imported via `use Trait as _;`. - unnamed_trait_imports: FxHashMap>, + unnamed_trait_imports: ThinVec<(TraitId, Item<()>)>, // the resolutions of the imports of this scope use_imports_types: FxHashMap, use_imports_values: FxHashMap, use_imports_macros: FxHashMap, - use_decls: Vec, - extern_crate_decls: Vec, + use_decls: ThinVec, + extern_crate_decls: ThinVec, /// Macros visible in current module in legacy textual scope /// /// For macros invoked by an unqualified identifier like `bar!()`, `legacy_macros` will be searched in first. @@ -183,7 +183,7 @@ pub struct ItemScope { /// Module scoped macros will be inserted into `items` instead of here. // FIXME: Macro shadowing in one module is not properly handled. Non-item place macros will // be all resolved to the last one defined if shadowing happens. - legacy_macros: FxHashMap>, + legacy_macros: FxHashMap>, /// The attribute macro invocations in this scope. attr_macros: FxHashMap, MacroCallId>, /// The macro invocations in this scope. @@ -198,7 +198,7 @@ struct DeriveMacroInvocation { attr_id: AttrId, /// The `#[derive]` call attr_call_id: MacroCallId, - derive_call_ids: SmallVec<[Option; 1]>, + derive_call_ids: SmallVec<[Option; 4]>, } pub(crate) static BUILTIN_SCOPE: LazyLock> = LazyLock::new(|| { @@ -322,7 +322,7 @@ impl ItemScope { } pub fn extern_blocks(&self) -> impl Iterator + '_ { - self.extern_blocks.iter().flat_map(|it| it.iter()).copied() + self.extern_blocks.iter().copied() } pub fn use_decls(&self) -> impl ExactSizeIterator + '_ { @@ -435,7 +435,7 @@ impl ItemScope { ModuleDefId::TraitId(t) => Some(t), _ => None, }) - .chain(self.unnamed_trait_imports.keys().copied()) + .chain(self.unnamed_trait_imports.iter().map(|&(t, _)| t)) } pub(crate) fn resolutions(&self) -> impl Iterator, PerNs)> + '_ { @@ -476,7 +476,7 @@ impl ItemScope { } pub(crate) fn define_extern_block(&mut self, extern_block: ExternBlockId) { - self.extern_blocks.get_or_insert_default().push(extern_block); + self.extern_blocks.push(extern_block); } pub(crate) fn define_extern_crate_decl(&mut self, extern_crate: ExternCrateId) { @@ -564,7 +564,7 @@ impl ItemScope { // FIXME: This is only used in collection, we should move the relevant parts of it out of ItemScope pub(crate) fn unnamed_trait_vis(&self, tr: TraitId) -> Option { - self.unnamed_trait_imports.get(&tr).map(|trait_| trait_.vis) + self.unnamed_trait_imports.iter().find(|&&(t, _)| t == tr).map(|(_, trait_)| trait_.vis) } pub(crate) fn push_unnamed_trait( @@ -573,7 +573,7 @@ impl ItemScope { vis: Visibility, import: Option, ) { - self.unnamed_trait_imports.insert(tr, Item { def: (), vis, import }); + self.unnamed_trait_imports.push((tr, Item { def: (), vis, import })); } pub(crate) fn push_res_with_import( @@ -725,7 +725,7 @@ impl ItemScope { .values_mut() .map(|def| &mut def.vis) .chain(self.values.values_mut().map(|def| &mut def.vis)) - .chain(self.unnamed_trait_imports.values_mut().map(|def| &mut def.vis)) + .chain(self.unnamed_trait_imports.iter_mut().map(|(_, def)| &mut def.vis)) .for_each(|vis| match vis { &mut Visibility::Module(_, visibility_explicitness) => { *vis = Visibility::Module(this_module, visibility_explicitness) @@ -817,9 +817,7 @@ impl ItemScope { macro_invocations, extern_blocks, } = self; - if let Some(it) = extern_blocks { - it.shrink_to_fit(); - } + extern_blocks.shrink_to_fit(); types.shrink_to_fit(); values.shrink_to_fit(); macros.shrink_to_fit(); From 5702eadd27c03d9ecdc35a4a283aeece274ef9f8 Mon Sep 17 00:00:00 2001 From: Martin Pool Date: Fri, 13 Jun 2025 07:35:03 -0700 Subject: [PATCH 39/56] Fix link to the contribution guide --- docs/book/src/troubleshooting.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/book/src/troubleshooting.md b/docs/book/src/troubleshooting.md index 4092b9de99..1b2841421a 100644 --- a/docs/book/src/troubleshooting.md +++ b/docs/book/src/troubleshooting.md @@ -46,5 +46,4 @@ It is especially useful when the `repo` doesn’t use external crates or the standard library. If you want to go as far as to modify the source code to debug the -problem, be sure to take a look at the [dev -docs](https://github.com/rust-lang/rust-analyzer/tree/master/docs/dev)! +problem, be sure to take a look at the [contribution guide](contributing/index.html)! From e3c75abe67ffa988c5182df808ef5cb8e0ec05e4 Mon Sep 17 00:00:00 2001 From: Martin Pool Date: Fri, 13 Jun 2025 07:36:40 -0700 Subject: [PATCH 40/56] Make the URL a hyperlink --- docs/book/src/contributing/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/book/src/contributing/README.md b/docs/book/src/contributing/README.md index 5f4a74eba2..beb94cdfc4 100644 --- a/docs/book/src/contributing/README.md +++ b/docs/book/src/contributing/README.md @@ -13,7 +13,7 @@ To learn more about how rust-analyzer works, see [Architecture](architecture.md) It also explains the high-level layout of the source code. Do skim through that document. -We also publish rustdoc docs to pages: https://rust-lang.github.io/rust-analyzer/ide/. +We also publish rustdoc docs to . Note though, that the internal documentation is very incomplete. Various organizational and process issues are discussed in this document. From 8643a858dbaf12b37e90b603cdee64434576c229 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 13 Jun 2025 17:15:28 +0200 Subject: [PATCH 41/56] Turn `BlockId` into a `#[salsa::tracked]` --- crates/hir-def/src/db.rs | 11 ++++------ crates/hir-def/src/expr_store/lower.rs | 4 ++-- .../src/expr_store/tests/body/block.rs | 4 ++-- crates/hir-def/src/lib.rs | 21 ++++++++++++++++++- 4 files changed, 28 insertions(+), 12 deletions(-) diff --git a/crates/hir-def/src/db.rs b/crates/hir-def/src/db.rs index 27fe62c4f0..f024f04efe 100644 --- a/crates/hir-def/src/db.rs +++ b/crates/hir-def/src/db.rs @@ -12,10 +12,10 @@ use thin_vec::ThinVec; 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, MacroExpander, - MacroId, MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ProcMacroId, ProcMacroLoc, StaticId, + AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, EnumVariantId, EnumVariantLoc, + ExternBlockId, ExternBlockLoc, ExternCrateId, ExternCrateLoc, FunctionId, 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}, @@ -96,9 +96,6 @@ pub trait InternDatabase: RootQueryDb { #[salsa::interned] fn intern_macro_rules(&self, loc: MacroRulesLoc) -> MacroRulesId; // // endregion: items - - #[salsa::interned] - fn intern_block(&self, loc: BlockLoc) -> BlockId; } #[query_group::query_group] diff --git a/crates/hir-def/src/expr_store/lower.rs b/crates/hir-def/src/expr_store/lower.rs index 4ba31c1e20..03683ec920 100644 --- a/crates/hir-def/src/expr_store/lower.rs +++ b/crates/hir-def/src/expr_store/lower.rs @@ -11,7 +11,7 @@ use base_db::FxIndexSet; use cfg::CfgOptions; use either::Either; use hir_expand::{ - HirFileId, InFile, MacroDefId, + HirFileId, InFile, Intern, MacroDefId, mod_path::tool_path, name::{AsName, Name}, span_map::SpanMapRef, @@ -2148,7 +2148,7 @@ impl ExprCollector<'_> { ) -> ExprId { 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); - self.db.intern_block(BlockLoc { ast_id, module: self.module }) + BlockLoc { ast_id, module: self.module }.intern(self.db) }); let (module, def_map) = diff --git a/crates/hir-def/src/expr_store/tests/body/block.rs b/crates/hir-def/src/expr_store/tests/body/block.rs index 5f7b510bba..5fe7277817 100644 --- a/crates/hir-def/src/expr_store/tests/body/block.rs +++ b/crates/hir-def/src/expr_store/tests/body/block.rs @@ -189,8 +189,8 @@ fn f() { } "#, expect![[r#" - BlockId(3c01) in BlockRelativeModuleId { block: Some(BlockId(3c00)), local_id: Idx::(1) } - BlockId(3c00) in BlockRelativeModuleId { block: None, local_id: Idx::(0) } + BlockIdLt { [salsa id]: Id(3c01) } in BlockRelativeModuleId { block: Some(BlockIdLt { [salsa id]: Id(3c00) }), local_id: Idx::(1) } + BlockIdLt { [salsa id]: Id(3c00) } in BlockRelativeModuleId { block: None, local_id: Idx::(0) } crate scope "#]], ); diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs index dcc18666a5..e7ab2b4d77 100644 --- a/crates/hir-def/src/lib.rs +++ b/crates/hir-def/src/lib.rs @@ -344,7 +344,26 @@ pub struct BlockLoc { /// The containing module. pub module: ModuleId, } -impl_intern!(BlockId, BlockLoc, intern_block, lookup_intern_block); +#[salsa_macros::tracked(debug)] +#[derive(PartialOrd, Ord)] +pub struct BlockIdLt<'db> { + pub loc: BlockLoc, +} +pub type BlockId = BlockIdLt<'static>; +impl hir_expand::Intern for BlockLoc { + type Database = dyn DefDatabase; + type ID = BlockId; + fn intern(self, db: &Self::Database) -> Self::ID { + unsafe { std::mem::transmute::, BlockId>(BlockIdLt::new(db, self)) } + } +} +impl hir_expand::Lookup for BlockId { + type Database = dyn DefDatabase; + type Data = BlockLoc; + fn lookup(&self, db: &Self::Database) -> Self::Data { + self.loc(db) + } +} /// A `ModuleId` that is always a crate's root module. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] From 133418e3cc03843f68a865c200b0f08aea35a18d Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 13 Jun 2025 17:29:22 +0200 Subject: [PATCH 42/56] Remove `InternedCallableDefId` It's unnecessary --- crates/hir-ty/src/chalk_ext.rs | 12 ++++++------ crates/hir-ty/src/db.rs | 7 ------- crates/hir-ty/src/lib.rs | 4 ++-- crates/hir-ty/src/mapping.rs | 20 ++++---------------- crates/hir-ty/src/mir/eval.rs | 4 ++-- crates/hir-ty/src/mir/lower/as_place.rs | 9 +++------ crates/hir/src/source_analyzer.rs | 5 ++--- 7 files changed, 19 insertions(+), 42 deletions(-) diff --git a/crates/hir-ty/src/chalk_ext.rs b/crates/hir-ty/src/chalk_ext.rs index aabc4c4234..836cc96233 100644 --- a/crates/hir-ty/src/chalk_ext.rs +++ b/crates/hir-ty/src/chalk_ext.rs @@ -16,7 +16,8 @@ use crate::{ ClosureId, DynTy, FnPointer, ImplTraitId, InEnvironment, Interner, Lifetime, ProjectionTy, QuantifiedWhereClause, Substitution, TraitRef, Ty, TyBuilder, TyKind, TypeFlags, WhereClause, db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, - from_placeholder_idx, generics::generics, to_chalk_trait_id, utils::ClosureSubst, + from_placeholder_idx, generics::generics, mapping::ToChalk, to_chalk_trait_id, + utils::ClosureSubst, }; pub trait TyExt { @@ -190,10 +191,9 @@ impl TyExt for Ty { fn as_generic_def(&self, db: &dyn HirDatabase) -> Option { match *self.kind(Interner) { TyKind::Adt(AdtId(adt), ..) => Some(adt.into()), - TyKind::FnDef(callable, ..) => Some(GenericDefId::from_callable( - db, - db.lookup_intern_callable_def(callable.into()), - )), + TyKind::FnDef(callable, ..) => { + Some(GenericDefId::from_callable(db, ToChalk::from_chalk(db, callable))) + } TyKind::AssociatedType(type_alias, ..) => Some(from_assoc_type_id(type_alias).into()), TyKind::Foreign(type_alias, ..) => Some(from_foreign_def_id(type_alias).into()), _ => None, @@ -202,7 +202,7 @@ impl TyExt for Ty { fn callable_def(&self, db: &dyn HirDatabase) -> Option { match self.kind(Interner) { - &TyKind::FnDef(def, ..) => Some(db.lookup_intern_callable_def(def.into())), + &TyKind::FnDef(def, ..) => Some(ToChalk::from_chalk(db, def)), _ => None, } } diff --git a/crates/hir-ty/src/db.rs b/crates/hir-ty/src/db.rs index 1e985dc604..1029969992 100644 --- a/crates/hir-ty/src/db.rs +++ b/crates/hir-ty/src/db.rs @@ -236,9 +236,6 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { fn trait_impls_in_deps(&self, krate: Crate) -> Arc<[Arc]>; // Interned IDs for Chalk integration - #[salsa::interned] - fn intern_callable_def(&self, callable_def: CallableDefId) -> InternedCallableDefId; - #[salsa::interned] fn intern_type_or_const_param_id( &self, @@ -347,7 +344,3 @@ impl_intern_key!(InternedClosureId, InternedClosure); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct InternedCoroutine(pub DefWithBodyId, pub ExprId); impl_intern_key!(InternedCoroutineId, InternedCoroutine); - -// This exists just for Chalk, because Chalk just has a single `FnDefId` where -// we have different IDs for struct and enum variant constructors. -impl_intern_key!(InternedCallableDefId, CallableDefId); diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs index 128569d55d..148f2a41e7 100644 --- a/crates/hir-ty/src/lib.rs +++ b/crates/hir-ty/src/lib.rs @@ -98,7 +98,7 @@ pub use lower::{ ValueTyDefId, associated_type_shorthand_candidates, diagnostics::*, }; pub use mapping::{ - from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, from_placeholder_idx, + ToChalk, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, from_placeholder_idx, lt_from_placeholder_idx, lt_to_placeholder_idx, to_assoc_type_id, to_chalk_trait_id, to_foreign_def_id, to_placeholder_idx, }; @@ -542,7 +542,7 @@ impl CallableSig { } pub fn from_def(db: &dyn HirDatabase, def: FnDefId, substs: &Substitution) -> CallableSig { - let callable_def = db.lookup_intern_callable_def(def.into()); + let callable_def = ToChalk::from_chalk(db, def); let sig = db.callable_item_signature(callable_def); sig.substitute(Interner, substs) } diff --git a/crates/hir-ty/src/mapping.rs b/crates/hir-ty/src/mapping.rs index 2abc1ac62a..6936d8193e 100644 --- a/crates/hir-ty/src/mapping.rs +++ b/crates/hir-ty/src/mapping.rs @@ -16,7 +16,7 @@ use crate::{ PlaceholderIndex, chalk_db, db::HirDatabase, }; -pub(crate) trait ToChalk { +pub trait ToChalk { type Chalk; fn to_chalk(self, db: &dyn HirDatabase) -> Self::Chalk; fn from_chalk(db: &dyn HirDatabase, chalk: Self::Chalk) -> Self; @@ -44,12 +44,12 @@ impl ToChalk for hir_def::ImplId { impl ToChalk for CallableDefId { type Chalk = FnDefId; - fn to_chalk(self, db: &dyn HirDatabase) -> FnDefId { - db.intern_callable_def(self).into() + fn to_chalk(self, _db: &dyn HirDatabase) -> FnDefId { + chalk_ir::FnDefId(salsa::plumbing::AsId::as_id(&self)) } fn from_chalk(db: &dyn HirDatabase, fn_def_id: FnDefId) -> CallableDefId { - db.lookup_intern_callable_def(fn_def_id.into()) + salsa::plumbing::FromIdWithDb::from_id(fn_def_id.0, db.zalsa()) } } @@ -70,18 +70,6 @@ impl ToChalk for TypeAliasAsValue { } } -impl From for crate::db::InternedCallableDefId { - fn from(fn_def_id: FnDefId) -> Self { - Self::from_id(fn_def_id.0) - } -} - -impl From for FnDefId { - fn from(callable_def_id: crate::db::InternedCallableDefId) -> Self { - chalk_ir::FnDefId(callable_def_id.as_id()) - } -} - impl From for crate::db::InternedOpaqueTyId { fn from(id: OpaqueTyId) -> Self { FromId::from_id(id.0) diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs index 8fb8d64779..da6e4e5d8a 100644 --- a/crates/hir-ty/src/mir/eval.rs +++ b/crates/hir-ty/src/mir/eval.rs @@ -32,7 +32,7 @@ use triomphe::Arc; use crate::{ CallableDefId, ClosureId, ComplexMemoryMap, Const, ConstData, ConstScalar, FnDefId, Interner, - MemoryMap, Substitution, TraitEnvironment, Ty, TyBuilder, TyExt, TyKind, + MemoryMap, Substitution, ToChalk, TraitEnvironment, Ty, TyBuilder, TyExt, TyKind, consteval::{ConstEvalError, intern_const_scalar, try_const_usize}, db::{HirDatabase, InternedClosure}, display::{ClosureStyle, DisplayTarget, HirDisplay}, @@ -2930,7 +2930,7 @@ pub fn render_const_using_debug_impl( let a2 = evaluator.heap_allocate(evaluator.ptr_size() * 2, evaluator.ptr_size())?; evaluator.write_memory(a2, &data.addr.to_bytes())?; let debug_fmt_fn_ptr = evaluator.vtable_map.id(TyKind::FnDef( - db.intern_callable_def(debug_fmt_fn.into()).into(), + CallableDefId::FunctionId(debug_fmt_fn).to_chalk(db), Substitution::from1(Interner, c.data(Interner).ty.clone()), ) .intern(Interner)); diff --git a/crates/hir-ty/src/mir/lower/as_place.rs b/crates/hir-ty/src/mir/lower/as_place.rs index c22bada7a9..ad664693e2 100644 --- a/crates/hir-ty/src/mir/lower/as_place.rs +++ b/crates/hir-ty/src/mir/lower/as_place.rs @@ -297,11 +297,8 @@ impl MirLowerCtx<'_> { let result_ref = TyKind::Ref(mutability, error_lifetime(), result_ty).intern(Interner); let mut result: Place = self.temp(result_ref, current, span)?.into(); let index_fn_op = Operand::const_zst( - TyKind::FnDef( - self.db.intern_callable_def(CallableDefId::FunctionId(index_fn.0)).into(), - index_fn.1, - ) - .intern(Interner), + TyKind::FnDef(CallableDefId::FunctionId(index_fn.0).to_chalk(self.db), index_fn.1) + .intern(Interner), ); let Some(current) = self.lower_call( index_fn_op, @@ -357,7 +354,7 @@ impl MirLowerCtx<'_> { .ok_or(MirLowerError::LangItemNotFound(trait_lang_item))?; let deref_fn_op = Operand::const_zst( TyKind::FnDef( - self.db.intern_callable_def(CallableDefId::FunctionId(deref_fn)).into(), + CallableDefId::FunctionId(deref_fn).to_chalk(self.db), Substitution::from1(Interner, source_ty), ) .intern(Interner), diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index ec2ccf8cba..09b61524d6 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -37,7 +37,7 @@ use hir_expand::{ }; use hir_ty::{ Adjustment, AliasTy, InferenceResult, Interner, LifetimeElisionKind, ProjectionTy, - Substitution, TraitEnvironment, Ty, TyExt, TyKind, TyLoweringContext, + Substitution, ToChalk, TraitEnvironment, Ty, TyExt, TyKind, TyLoweringContext, diagnostics::{ InsideUnsafeBlock, record_literal_missing_fields, record_pattern_missing_fields, unsafe_operations, @@ -1169,8 +1169,7 @@ impl<'db> SourceAnalyzer<'db> { ) } TyKind::FnDef(fn_id, subst) => { - let fn_id = hir_ty::db::InternedCallableDefId::from(*fn_id); - let fn_id = db.lookup_intern_callable_def(fn_id); + let fn_id = ToChalk::from_chalk(db, *fn_id); let generic_def_id = match fn_id { CallableDefId::StructId(id) => id.into(), CallableDefId::FunctionId(id) => id.into(), From cfc416a7bacb4e5b86a225cd3841a898194ab85c Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Thu, 12 Jun 2025 14:03:18 +0200 Subject: [PATCH 43/56] remove `pref_align_of` intrinsic handling, rename `{min_=>}align_of{,_val}` --- crates/hir-ty/src/consteval/tests/intrinsics.rs | 10 +++++----- crates/hir-ty/src/mir/eval/shim.rs | 12 ++++++++---- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/crates/hir-ty/src/consteval/tests/intrinsics.rs b/crates/hir-ty/src/consteval/tests/intrinsics.rs index ee375d60de..5e85978e29 100644 --- a/crates/hir-ty/src/consteval/tests/intrinsics.rs +++ b/crates/hir-ty/src/consteval/tests/intrinsics.rs @@ -112,16 +112,16 @@ fn size_of_val() { } #[test] -fn min_align_of_val() { +fn align_of_val() { check_number( r#" //- minicore: coerce_unsized #[rustc_intrinsic] - pub fn min_align_of_val(_: *const T) -> usize; + pub fn align_of_val(_: *const T) -> usize; struct X(i32, u8); - const GOAL: usize = min_align_of_val(&X(1, 2)); + const GOAL: usize = align_of_val(&X(1, 2)); "#, 4, ); @@ -129,11 +129,11 @@ fn min_align_of_val() { r#" //- minicore: coerce_unsized #[rustc_intrinsic] - pub fn min_align_of_val(_: *const T) -> usize; + pub fn align_of_val(_: *const T) -> usize; const GOAL: usize = { let x: &[i32] = &[1, 2, 3]; - min_align_of_val(x) + align_of_val(x) }; "#, 4, diff --git a/crates/hir-ty/src/mir/eval/shim.rs b/crates/hir-ty/src/mir/eval/shim.rs index 512a275aa7..8d428dd6d0 100644 --- a/crates/hir-ty/src/mir/eval/shim.rs +++ b/crates/hir-ty/src/mir/eval/shim.rs @@ -761,7 +761,9 @@ impl Evaluator<'_> { let size = self.size_of_sized(ty, locals, "size_of arg")?; destination.write_from_bytes(self, &size.to_le_bytes()[0..destination.size]) } - "min_align_of" | "pref_align_of" => { + // FIXME: `min_align_of` was renamed to `align_of` in Rust 1.89 + // (https://github.com/rust-lang/rust/pull/142410) + "min_align_of" | "align_of" => { let Some(ty) = generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner)) else { @@ -793,17 +795,19 @@ impl Evaluator<'_> { destination.write_from_bytes(self, &size.to_le_bytes()) } } - "min_align_of_val" => { + // FIXME: `min_align_of_val` was renamed to `align_of_val` in Rust 1.89 + // (https://github.com/rust-lang/rust/pull/142410) + "min_align_of_val" | "align_of_val" => { let Some(ty) = generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner)) else { return Err(MirEvalError::InternalError( - "min_align_of_val generic arg is not provided".into(), + "align_of_val generic arg is not provided".into(), )); }; let [arg] = args else { return Err(MirEvalError::InternalError( - "min_align_of_val args are not provided".into(), + "align_of_val args are not provided".into(), )); }; if let Some((_, align)) = self.size_align_of(ty, locals)? { From a7c09532a08c1a82830cd3a2edc31e99b1c07990 Mon Sep 17 00:00:00 2001 From: Tadeo Kondrak Date: Fri, 13 Jun 2025 17:51:10 -0600 Subject: [PATCH 44/56] Allow lifetime repeats in macros: $($x)'a* This works in rustc. This change isn't motivated by any real code. I just learned about it and decided to see why it doesn't work with rust-analyzer. --- .../hir-def/src/macro_expansion_tests/mbe.rs | 22 +++++++++++++++++++ .../macro_expansion_tests/mbe/meta_syntax.rs | 4 ++++ crates/mbe/src/benchmark.rs | 4 ++++ crates/mbe/src/expander/matcher.rs | 11 ++++++---- crates/mbe/src/expander/transcriber.rs | 4 ++++ crates/mbe/src/parser.rs | 19 ++++++++++++---- 6 files changed, 56 insertions(+), 8 deletions(-) diff --git a/crates/hir-def/src/macro_expansion_tests/mbe.rs b/crates/hir-def/src/macro_expansion_tests/mbe.rs index eea50d16f5..ef93a2a790 100644 --- a/crates/hir-def/src/macro_expansion_tests/mbe.rs +++ b/crates/hir-def/src/macro_expansion_tests/mbe.rs @@ -2029,3 +2029,25 @@ fn f() { "#]], ); } + +#[test] +fn lifetime_repeat() { + check( + r#" +macro_rules! m { + ($($x:expr)'a*) => (stringify!($($x)'b*)); +} +fn f() { + let _ = m!(0 'a 1 'a 2); +} + "#, + expect![[r#" +macro_rules! m { + ($($x:expr)'a*) => (stringify!($($x)'b*)); +} +fn f() { + let _ = stringify!(0 'b1 'b2); +} + "#]], + ); +} diff --git a/crates/hir-def/src/macro_expansion_tests/mbe/meta_syntax.rs b/crates/hir-def/src/macro_expansion_tests/mbe/meta_syntax.rs index 2d289b7683..2c94f0e8d0 100644 --- a/crates/hir-def/src/macro_expansion_tests/mbe/meta_syntax.rs +++ b/crates/hir-def/src/macro_expansion_tests/mbe/meta_syntax.rs @@ -13,6 +13,8 @@ macro_rules! m { ($(x),*) => (); ($(x)_*) => (); ($(x)i*) => (); + ($(x)'a*) => (); + ($(x)'_*) => (); ($($i:ident)*) => ($_); ($($true:ident)*) => ($true); ($($false:ident)*) => ($false); @@ -28,6 +30,8 @@ macro_rules! m { ($(x),*) => (); ($(x)_*) => (); ($(x)i*) => (); + ($(x)'a*) => (); + ($(x)'_*) => (); ($($i:ident)*) => ($_); ($($true:ident)*) => ($true); ($($false:ident)*) => ($false); diff --git a/crates/mbe/src/benchmark.rs b/crates/mbe/src/benchmark.rs index db75dceae1..04ac85ad43 100644 --- a/crates/mbe/src/benchmark.rs +++ b/crates/mbe/src/benchmark.rs @@ -197,6 +197,10 @@ fn invocation_fixtures( builder.push(tt::Leaf::Punct(*it)) } } + Separator::Lifetime(punct, ident) => { + builder.push(tt::Leaf::Punct(*punct)); + builder.push(tt::Leaf::Ident(ident.clone())); + } }; } } diff --git a/crates/mbe/src/expander/matcher.rs b/crates/mbe/src/expander/matcher.rs index 940aaacb02..a8d5965d48 100644 --- a/crates/mbe/src/expander/matcher.rs +++ b/crates/mbe/src/expander/matcher.rs @@ -823,7 +823,7 @@ fn match_meta_var<'t>( "expected token tree", ) }), - MetaVarKind::Lifetime => expect_lifetime(input).map_err(|()| { + MetaVarKind::Lifetime => expect_lifetime(input).map(drop).map_err(|()| { ExpandError::binding_error( span.unwrap_or(delim_span.close), "expected lifetime", @@ -963,6 +963,10 @@ fn expect_separator(iter: &mut TtIter<'_, S>, separator: &Separator) -> } Err(_) => false, }, + Separator::Lifetime(_punct, ident) => match expect_lifetime(&mut fork) { + Ok(lifetime) => lifetime.sym == ident.sym, + Err(_) => false, + }, }; if ok { *iter = fork; @@ -983,13 +987,12 @@ fn expect_tt(iter: &mut TtIter<'_, S>) -> Result<(), ()> { Ok(()) } -fn expect_lifetime(iter: &mut TtIter<'_, S>) -> Result<(), ()> { +fn expect_lifetime<'a, S: Copy>(iter: &mut TtIter<'a, S>) -> Result<&'a tt::Ident, ()> { let punct = iter.expect_single_punct()?; if punct.char != '\'' { return Err(()); } - iter.expect_ident_or_underscore()?; - Ok(()) + iter.expect_ident_or_underscore() } fn eat_char(iter: &mut TtIter<'_, S>, c: char) { diff --git a/crates/mbe/src/expander/transcriber.rs b/crates/mbe/src/expander/transcriber.rs index ec277ba72e..2c046df10f 100644 --- a/crates/mbe/src/expander/transcriber.rs +++ b/crates/mbe/src/expander/transcriber.rs @@ -497,6 +497,10 @@ fn expand_repeat( builder.push(tt::Leaf::from(punct)); } } + Separator::Lifetime(punct, ident) => { + builder.push(tt::Leaf::from(*punct)); + builder.push(tt::Leaf::from(ident.clone())); + } }; } diff --git a/crates/mbe/src/parser.rs b/crates/mbe/src/parser.rs index fbc353d610..711101260a 100644 --- a/crates/mbe/src/parser.rs +++ b/crates/mbe/src/parser.rs @@ -155,6 +155,7 @@ pub(crate) enum Separator { Literal(tt::Literal), Ident(tt::Ident), Puncts(ArrayVec, MAX_GLUED_PUNCT_LEN>), + Lifetime(tt::Punct, tt::Ident), } // Note that when we compare a Separator, we just care about its textual value. @@ -170,6 +171,7 @@ impl PartialEq for Separator { let b_iter = b.iter().map(|b| b.char); a_iter.eq(b_iter) } + (Lifetime(_, a), Lifetime(_, b)) => a.sym == b.sym, _ => false, } } @@ -350,10 +352,19 @@ fn parse_repeat(src: &mut TtIter<'_, Span>) -> Result<(Option, Repeat _ => true, }; match tt { - tt::Leaf::Ident(_) | tt::Leaf::Literal(_) if has_sep => { - return Err(ParseError::InvalidRepeat); - } - tt::Leaf::Ident(ident) => separator = Separator::Ident(ident.clone()), + tt::Leaf::Ident(ident) => match separator { + Separator::Puncts(puncts) if puncts.is_empty() => { + separator = Separator::Ident(ident.clone()); + } + Separator::Puncts(puncts) => match puncts.as_slice() { + [tt::Punct { char: '\'', .. }] => { + separator = Separator::Lifetime(puncts[0], ident.clone()); + } + _ => return Err(ParseError::InvalidRepeat), + }, + _ => return Err(ParseError::InvalidRepeat), + }, + tt::Leaf::Literal(_) if has_sep => return Err(ParseError::InvalidRepeat), tt::Leaf::Literal(lit) => separator = Separator::Literal(lit.clone()), tt::Leaf::Punct(punct) => { let repeat_kind = match punct.char { From dc85e3ee3528a6f452b298591866c5aadea982f6 Mon Sep 17 00:00:00 2001 From: Lucas Holten Date: Sun, 15 Jun 2025 02:41:35 +0200 Subject: [PATCH 45/56] Add config option to exclude imports from symbol search --- crates/hir/src/symbols.rs | 7 ++ crates/ide-db/src/symbol_index.rs | 39 ++++++++++- .../ide-db/src/test_data/test_doc_alias.txt | 7 ++ .../test_symbol_index_collection.txt | 31 ++++++++ .../test_symbols_exclude_imports.txt | 36 ++++++++++ .../test_data/test_symbols_with_imports.txt | 70 +++++++++++++++++++ crates/rust-analyzer/src/config.rs | 5 ++ crates/rust-analyzer/src/handlers/request.rs | 3 + docs/book/src/configuration_generated.md | 7 ++ editors/code/package.json | 10 +++ 10 files changed, 214 insertions(+), 1 deletion(-) create mode 100644 crates/ide-db/src/test_data/test_symbols_exclude_imports.txt create mode 100644 crates/ide-db/src/test_data/test_symbols_with_imports.txt diff --git a/crates/hir/src/symbols.rs b/crates/hir/src/symbols.rs index a0815c3131..4b295fe9ec 100644 --- a/crates/hir/src/symbols.rs +++ b/crates/hir/src/symbols.rs @@ -33,6 +33,7 @@ pub struct FileSymbol { /// Whether this symbol is a doc alias for the original symbol. pub is_alias: bool, pub is_assoc: bool, + pub is_import: bool, pub do_not_complete: Complete, } @@ -196,6 +197,7 @@ impl<'a> SymbolCollector<'a> { loc: dec_loc, is_alias: false, is_assoc: false, + is_import: true, do_not_complete: Complete::Yes, }); }; @@ -226,6 +228,7 @@ impl<'a> SymbolCollector<'a> { loc: dec_loc, is_alias: false, is_assoc: false, + is_import: false, do_not_complete: Complete::Yes, }); }; @@ -397,6 +400,7 @@ impl<'a> SymbolCollector<'a> { container_name: self.current_container_name.clone(), is_alias: true, is_assoc, + is_import: false, do_not_complete, }); } @@ -409,6 +413,7 @@ impl<'a> SymbolCollector<'a> { loc: dec_loc, is_alias: false, is_assoc, + is_import: false, do_not_complete, }); @@ -441,6 +446,7 @@ impl<'a> SymbolCollector<'a> { container_name: self.current_container_name.clone(), is_alias: true, is_assoc: false, + is_import: false, do_not_complete, }); } @@ -453,6 +459,7 @@ impl<'a> SymbolCollector<'a> { loc: dec_loc, is_alias: false, is_assoc: false, + is_import: false, do_not_complete, }); } diff --git a/crates/ide-db/src/symbol_index.rs b/crates/ide-db/src/symbol_index.rs index d1ba79e8c7..c15cade84a 100644 --- a/crates/ide-db/src/symbol_index.rs +++ b/crates/ide-db/src/symbol_index.rs @@ -50,6 +50,7 @@ pub struct Query { case_sensitive: bool, only_types: bool, libs: bool, + exclude_imports: bool, } impl Query { @@ -63,6 +64,7 @@ impl Query { mode: SearchMode::Fuzzy, assoc_mode: AssocSearchMode::Include, case_sensitive: false, + exclude_imports: false, } } @@ -94,6 +96,10 @@ impl Query { pub fn case_sensitive(&mut self) { self.case_sensitive = true; } + + pub fn exclude_imports(&mut self) { + self.exclude_imports = true; + } } #[query_group::query_group] @@ -362,6 +368,9 @@ impl Query { if ignore_underscore_prefixed && symbol_name.starts_with("__") { continue; } + if self.exclude_imports && symbol.is_import { + continue; + } if self.mode.check(&self.query, self.case_sensitive, symbol_name) { if let Some(b) = cb(symbol).break_value() { return Some(b); @@ -385,7 +394,8 @@ impl Query { mod tests { use expect_test::expect_file; - use test_fixture::WithFixture; + use salsa::Durability; + use test_fixture::{WORKSPACE, WithFixture}; use super::*; @@ -506,4 +516,31 @@ struct Duplicate; expect_file!["./test_data/test_doc_alias.txt"].assert_debug_eq(&symbols); } + + #[test] + fn test_exclude_imports() { + let (mut db, _) = RootDatabase::with_many_files( + r#" +//- /lib.rs +mod foo; +pub use foo::Foo; + +//- /foo.rs +pub struct Foo; +"#, + ); + + let mut local_roots = FxHashSet::default(); + local_roots.insert(WORKSPACE); + db.set_local_roots_with_durability(Arc::new(local_roots), Durability::HIGH); + + let mut query = Query::new("Foo".to_owned()); + let mut symbols = world_symbols(&db, query.clone()); + symbols.sort_by_key(|x| x.is_import); + expect_file!["./test_data/test_symbols_with_imports.txt"].assert_debug_eq(&symbols); + + query.exclude_imports(); + let symbols = world_symbols(&db, query); + expect_file!["./test_data/test_symbols_exclude_imports.txt"].assert_debug_eq(&symbols); + } } diff --git a/crates/ide-db/src/test_data/test_doc_alias.txt b/crates/ide-db/src/test_data/test_doc_alias.txt index 455a680590..30d1df4f8e 100644 --- a/crates/ide-db/src/test_data/test_doc_alias.txt +++ b/crates/ide-db/src/test_data/test_doc_alias.txt @@ -41,6 +41,7 @@ container_name: None, is_alias: false, is_assoc: false, + is_import: false, do_not_complete: Yes, }, FileSymbol { @@ -74,6 +75,7 @@ container_name: None, is_alias: false, is_assoc: false, + is_import: false, do_not_complete: Yes, }, FileSymbol { @@ -107,6 +109,7 @@ container_name: None, is_alias: true, is_assoc: false, + is_import: false, do_not_complete: Yes, }, FileSymbol { @@ -140,6 +143,7 @@ container_name: None, is_alias: true, is_assoc: false, + is_import: false, do_not_complete: Yes, }, FileSymbol { @@ -173,6 +177,7 @@ container_name: None, is_alias: true, is_assoc: false, + is_import: false, do_not_complete: Yes, }, FileSymbol { @@ -206,6 +211,7 @@ container_name: None, is_alias: true, is_assoc: false, + is_import: false, do_not_complete: Yes, }, FileSymbol { @@ -239,6 +245,7 @@ container_name: None, is_alias: true, is_assoc: false, + is_import: false, do_not_complete: Yes, }, ], diff --git a/crates/ide-db/src/test_data/test_symbol_index_collection.txt b/crates/ide-db/src/test_data/test_symbol_index_collection.txt index 5e5ae1d168..de046e70c6 100644 --- a/crates/ide-db/src/test_data/test_symbol_index_collection.txt +++ b/crates/ide-db/src/test_data/test_symbol_index_collection.txt @@ -39,6 +39,7 @@ container_name: None, is_alias: false, is_assoc: false, + is_import: false, do_not_complete: Yes, }, FileSymbol { @@ -70,6 +71,7 @@ container_name: None, is_alias: false, is_assoc: false, + is_import: false, do_not_complete: Yes, }, FileSymbol { @@ -101,6 +103,7 @@ container_name: None, is_alias: false, is_assoc: false, + is_import: false, do_not_complete: Yes, }, FileSymbol { @@ -134,6 +137,7 @@ container_name: None, is_alias: false, is_assoc: false, + is_import: false, do_not_complete: Yes, }, FileSymbol { @@ -167,6 +171,7 @@ container_name: None, is_alias: false, is_assoc: false, + is_import: true, do_not_complete: Yes, }, FileSymbol { @@ -200,6 +205,7 @@ container_name: None, is_alias: false, is_assoc: false, + is_import: false, do_not_complete: Yes, }, FileSymbol { @@ -231,6 +237,7 @@ container_name: None, is_alias: false, is_assoc: false, + is_import: false, do_not_complete: Yes, }, FileSymbol { @@ -264,6 +271,7 @@ container_name: None, is_alias: false, is_assoc: false, + is_import: false, do_not_complete: Yes, }, FileSymbol { @@ -297,6 +305,7 @@ container_name: None, is_alias: false, is_assoc: false, + is_import: false, do_not_complete: Yes, }, FileSymbol { @@ -332,6 +341,7 @@ ), is_alias: false, is_assoc: false, + is_import: false, do_not_complete: Yes, }, FileSymbol { @@ -367,6 +377,7 @@ ), is_alias: false, is_assoc: false, + is_import: false, do_not_complete: Yes, }, FileSymbol { @@ -400,6 +411,7 @@ container_name: None, is_alias: false, is_assoc: false, + is_import: false, do_not_complete: Yes, }, FileSymbol { @@ -433,6 +445,7 @@ container_name: None, is_alias: false, is_assoc: false, + is_import: false, do_not_complete: Yes, }, FileSymbol { @@ -464,6 +477,7 @@ container_name: None, is_alias: false, is_assoc: false, + is_import: false, do_not_complete: Yes, }, FileSymbol { @@ -497,6 +511,7 @@ container_name: None, is_alias: false, is_assoc: false, + is_import: true, do_not_complete: Yes, }, FileSymbol { @@ -530,6 +545,7 @@ container_name: None, is_alias: false, is_assoc: false, + is_import: false, do_not_complete: Yes, }, FileSymbol { @@ -565,6 +581,7 @@ container_name: None, is_alias: false, is_assoc: false, + is_import: false, do_not_complete: Yes, }, FileSymbol { @@ -600,6 +617,7 @@ container_name: None, is_alias: false, is_assoc: false, + is_import: false, do_not_complete: Yes, }, FileSymbol { @@ -633,6 +651,7 @@ container_name: None, is_alias: false, is_assoc: false, + is_import: false, do_not_complete: Yes, }, FileSymbol { @@ -666,6 +685,7 @@ ), is_alias: false, is_assoc: true, + is_import: false, do_not_complete: Yes, }, FileSymbol { @@ -699,6 +719,7 @@ ), is_alias: false, is_assoc: true, + is_import: false, do_not_complete: Yes, }, FileSymbol { @@ -732,6 +753,7 @@ container_name: None, is_alias: false, is_assoc: false, + is_import: false, do_not_complete: Yes, }, FileSymbol { @@ -763,6 +785,7 @@ container_name: None, is_alias: false, is_assoc: false, + is_import: false, do_not_complete: Yes, }, FileSymbol { @@ -796,6 +819,7 @@ container_name: None, is_alias: false, is_assoc: false, + is_import: true, do_not_complete: Yes, }, FileSymbol { @@ -829,6 +853,7 @@ ), is_alias: false, is_assoc: true, + is_import: false, do_not_complete: Yes, }, ], @@ -875,6 +900,7 @@ container_name: None, is_alias: false, is_assoc: false, + is_import: false, do_not_complete: Yes, }, ], @@ -919,6 +945,7 @@ container_name: None, is_alias: false, is_assoc: false, + is_import: true, do_not_complete: Yes, }, FileSymbol { @@ -952,6 +979,7 @@ container_name: None, is_alias: false, is_assoc: false, + is_import: true, do_not_complete: Yes, }, FileSymbol { @@ -985,6 +1013,7 @@ container_name: None, is_alias: false, is_assoc: false, + is_import: false, do_not_complete: Yes, }, FileSymbol { @@ -1018,6 +1047,7 @@ container_name: None, is_alias: false, is_assoc: false, + is_import: true, do_not_complete: Yes, }, FileSymbol { @@ -1051,6 +1081,7 @@ container_name: None, is_alias: false, is_assoc: false, + is_import: true, do_not_complete: Yes, }, ], diff --git a/crates/ide-db/src/test_data/test_symbols_exclude_imports.txt b/crates/ide-db/src/test_data/test_symbols_exclude_imports.txt new file mode 100644 index 0000000000..22872b577f --- /dev/null +++ b/crates/ide-db/src/test_data/test_symbols_exclude_imports.txt @@ -0,0 +1,36 @@ +[ + FileSymbol { + name: "Foo", + def: Adt( + Struct( + Struct { + id: StructId( + 3800, + ), + }, + ), + ), + loc: DeclarationLocation { + hir_file_id: FileId( + EditionedFileId( + Id(2001), + ), + ), + ptr: SyntaxNodePtr { + kind: STRUCT, + range: 0..15, + }, + name_ptr: AstPtr( + SyntaxNodePtr { + kind: NAME, + range: 11..14, + }, + ), + }, + container_name: None, + is_alias: false, + is_assoc: false, + is_import: false, + do_not_complete: Yes, + }, +] diff --git a/crates/ide-db/src/test_data/test_symbols_with_imports.txt b/crates/ide-db/src/test_data/test_symbols_with_imports.txt new file mode 100644 index 0000000000..9f98bf87e2 --- /dev/null +++ b/crates/ide-db/src/test_data/test_symbols_with_imports.txt @@ -0,0 +1,70 @@ +[ + FileSymbol { + name: "Foo", + def: Adt( + Struct( + Struct { + id: StructId( + 3800, + ), + }, + ), + ), + loc: DeclarationLocation { + hir_file_id: FileId( + EditionedFileId( + Id(2001), + ), + ), + ptr: SyntaxNodePtr { + kind: STRUCT, + range: 0..15, + }, + name_ptr: AstPtr( + SyntaxNodePtr { + kind: NAME, + range: 11..14, + }, + ), + }, + container_name: None, + is_alias: false, + is_assoc: false, + is_import: false, + do_not_complete: Yes, + }, + FileSymbol { + name: "Foo", + def: Adt( + Struct( + Struct { + id: StructId( + 3800, + ), + }, + ), + ), + loc: DeclarationLocation { + hir_file_id: FileId( + EditionedFileId( + Id(2000), + ), + ), + ptr: SyntaxNodePtr { + kind: USE_TREE, + range: 17..25, + }, + name_ptr: AstPtr( + SyntaxNodePtr { + kind: NAME_REF, + range: 22..25, + }, + ), + }, + container_name: None, + is_alias: false, + is_assoc: false, + is_import: true, + do_not_complete: Yes, + }, +] diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 5cbea9c2b3..762b63f54b 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -760,6 +760,8 @@ config_data! { /// though Cargo might be the eventual consumer. vfs_extraIncludes: Vec = vec![], + /// Exclude imports from symbol search. + workspace_symbol_search_excludeImports: bool = false, /// Workspace symbol search kind. workspace_symbol_search_kind: WorkspaceSymbolSearchKindDef = WorkspaceSymbolSearchKindDef::OnlyTypes, /// Limits the number of items returned from a workspace symbol search (Defaults to 128). @@ -1352,6 +1354,8 @@ pub struct RunnablesConfig { /// Configuration for workspace symbol search requests. #[derive(Debug, Clone)] pub struct WorkspaceSymbolConfig { + /// Should imports be excluded. + pub search_exclude_imports: bool, /// In what scope should the symbol be searched in. pub search_scope: WorkspaceSymbolSearchScope, /// What kind of symbol is being searched for. @@ -2280,6 +2284,7 @@ impl Config { pub fn workspace_symbol(&self, source_root: Option) -> WorkspaceSymbolConfig { WorkspaceSymbolConfig { + search_exclude_imports: *self.workspace_symbol_search_excludeImports(source_root), search_scope: match self.workspace_symbol_search_scope(source_root) { WorkspaceSymbolSearchScopeDef::Workspace => WorkspaceSymbolSearchScope::Workspace, WorkspaceSymbolSearchScopeDef::WorkspaceAndDependencies => { diff --git a/crates/rust-analyzer/src/handlers/request.rs b/crates/rust-analyzer/src/handlers/request.rs index 6d46ce68ed..afd9eff526 100644 --- a/crates/rust-analyzer/src/handlers/request.rs +++ b/crates/rust-analyzer/src/handlers/request.rs @@ -658,6 +658,9 @@ pub(crate) fn handle_workspace_symbol( if libs { q.libs(); } + if config.search_exclude_imports { + q.exclude_imports(); + } q }; let mut res = exec_query(&snap, query, config.search_limit)?; diff --git a/docs/book/src/configuration_generated.md b/docs/book/src/configuration_generated.md index 0e07dadfb7..4eb9cfc4e5 100644 --- a/docs/book/src/configuration_generated.md +++ b/docs/book/src/configuration_generated.md @@ -1531,6 +1531,13 @@ buck2's `rust-project` will likely be useful: https://github.com/facebook/buck2/tree/main/integrations/rust-project. +## rust-analyzer.workspace.symbol.search.excludeImports {#workspace.symbol.search.excludeImports} + +Default: `false` + +Exclude imports from symbol search. + + ## rust-analyzer.workspace.symbol.search.kind {#workspace.symbol.search.kind} Default: `"only_types"` diff --git a/editors/code/package.json b/editors/code/package.json index c8c36cd85c..dcdb4fe30e 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -2891,6 +2891,16 @@ } } }, + { + "title": "workspace", + "properties": { + "rust-analyzer.workspace.symbol.search.excludeImports": { + "markdownDescription": "Exclude imports from symbol search.", + "default": false, + "type": "boolean" + } + } + }, { "title": "workspace", "properties": { From f68512af65a359cc7489011a78beb8b315e67e01 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 14 Jun 2025 17:07:31 +0200 Subject: [PATCH 46/56] Cleanup incremental tests --- .../hir-def/src/nameres/tests/incremental.rs | 391 +++++++++---- crates/hir-ty/src/tests/incremental.rs | 520 ++++++++++++++---- 2 files changed, 695 insertions(+), 216 deletions(-) diff --git a/crates/hir-def/src/nameres/tests/incremental.rs b/crates/hir-def/src/nameres/tests/incremental.rs index 7a4ea62f12..858aa055ed 100644 --- a/crates/hir-def/src/nameres/tests/incremental.rs +++ b/crates/hir-def/src/nameres/tests/incremental.rs @@ -2,13 +2,13 @@ use base_db::{ CrateDisplayName, CrateGraphBuilder, CrateName, CrateOrigin, CrateWorkspaceData, DependencyBuilder, Env, RootQueryDb, SourceDatabase, }; +use expect_test::{Expect, expect}; use intern::Symbol; use span::Edition; use test_fixture::WithFixture; use triomphe::Arc; use crate::{ - AdtId, ModuleDefId, db::DefDatabase, nameres::{crate_def_map, tests::TestDB}, }; @@ -16,29 +16,29 @@ use crate::{ fn check_def_map_is_not_recomputed( #[rust_analyzer::rust_fixture] ra_fixture_initial: &str, #[rust_analyzer::rust_fixture] ra_fixture_change: &str, + expecta: Expect, + expectb: Expect, ) { let (mut db, pos) = TestDB::with_position(ra_fixture_initial); let krate = db.fetch_test_crate(); - { - let events = db.log_executed(|| { + execute_assert_events( + &db, + || { crate_def_map(&db, krate); - }); - assert!( - format!("{events:?}").contains("crate_local_def_map"), - "no crate def map computed:\n{events:#?}", - ) - } + }, + &[], + expecta, + ); db.set_file_text(pos.file_id.file_id(&db), ra_fixture_change); - { - let events = db.log_executed(|| { + execute_assert_events( + &db, + || { crate_def_map(&db, krate); - }); - assert!( - !format!("{events:?}").contains("crate_local_def_map"), - "crate def map invalidated:\n{events:#?}", - ) - } + }, + &[("crate_local_def_map", 0)], + expectb, + ); } #[test] @@ -104,15 +104,20 @@ pub const BAZ: u32 = 0; Arc::ptr_eq(&all_crates_before, &all_crates_after), "the all_crates list should not have been invalidated" ); - - let events = db.log_executed(|| { - for &krate in db.all_crates().iter() { - crate_def_map(&db, krate); - } - }); - let invalidated_def_maps = - events.iter().filter(|event| event.contains("crate_local_def_map")).count(); - assert_eq!(invalidated_def_maps, 1, "{events:#?}") + execute_assert_events( + &db, + || { + for &krate in db.all_crates().iter() { + crate_def_map(&db, krate); + } + }, + &[("crate_local_def_map", 1)], + expect![[r#" + [ + "crate_local_def_map", + ] + "#]], + ); } #[test] @@ -152,6 +157,34 @@ fn foo() -> i32 { 92 } #[cfg(never)] fn no() {} ", + expect![[r#" + [ + "crate_local_def_map", + "file_item_tree_query", + "ast_id_map_shim", + "parse_shim", + "real_span_map_shim", + "file_item_tree_query", + "ast_id_map_shim", + "parse_shim", + "real_span_map_shim", + "file_item_tree_query", + "ast_id_map_shim", + "parse_shim", + "real_span_map_shim", + "enum_variants_shim", + "enum_variants_with_diagnostics_shim", + ] + "#]], + expect![[r#" + [ + "parse_shim", + "ast_id_map_shim", + "file_item_tree_query", + "real_span_map_shim", + "enum_variants_with_diagnostics_shim", + ] + "#]], ); } @@ -183,6 +216,41 @@ m!(Y); pub struct S {} ", + expect![[r#" + [ + "crate_local_def_map", + "file_item_tree_query", + "ast_id_map_shim", + "parse_shim", + "real_span_map_shim", + "file_item_tree_query", + "ast_id_map_shim", + "parse_shim", + "real_span_map_shim", + "file_item_tree_query", + "ast_id_map_shim", + "parse_shim", + "real_span_map_shim", + "macro_def_shim", + "file_item_tree_query", + "ast_id_map_shim", + "parse_macro_expansion_shim", + "macro_arg_shim", + "decl_macro_expander_shim", + ] + "#]], + expect![[r#" + [ + "parse_shim", + "ast_id_map_shim", + "file_item_tree_query", + "real_span_map_shim", + "macro_arg_shim", + "parse_macro_expansion_shim", + "ast_id_map_shim", + "file_item_tree_query", + ] + "#]], ); } @@ -206,6 +274,49 @@ fn f() {} #[proc_macros::identity] fn f() { foo } ", + expect![[r#" + [ + "crate_local_def_map", + "file_item_tree_query", + "ast_id_map_shim", + "parse_shim", + "real_span_map_shim", + "file_item_tree_query", + "ast_id_map_shim", + "parse_shim", + "real_span_map_shim", + "file_item_tree_query", + "ast_id_map_shim", + "parse_shim", + "real_span_map_shim", + "crate_local_def_map", + "proc_macros_for_crate_shim", + "file_item_tree_query", + "ast_id_map_shim", + "parse_shim", + "real_span_map_shim", + "macro_def_shim", + "file_item_tree_query", + "ast_id_map_shim", + "parse_macro_expansion_shim", + "expand_proc_macro_shim", + "macro_arg_shim", + "proc_macro_span_shim", + ] + "#]], + expect![[r#" + [ + "parse_shim", + "ast_id_map_shim", + "file_item_tree_query", + "real_span_map_shim", + "macro_arg_shim", + "expand_proc_macro_shim", + "parse_macro_expansion_shim", + "ast_id_map_shim", + "file_item_tree_query", + ] + "#]], ); } @@ -287,6 +398,61 @@ m2!(X); #[derive(proc_macros::DeriveIdentity)] pub struct S {} ", + expect![[r#" + [ + "crate_local_def_map", + "file_item_tree_query", + "ast_id_map_shim", + "parse_shim", + "real_span_map_shim", + "file_item_tree_query", + "ast_id_map_shim", + "parse_shim", + "real_span_map_shim", + "file_item_tree_query", + "ast_id_map_shim", + "parse_shim", + "real_span_map_shim", + "macro_def_shim", + "file_item_tree_query", + "ast_id_map_shim", + "parse_macro_expansion_shim", + "macro_arg_shim", + "decl_macro_expander_shim", + "macro_def_shim", + "file_item_tree_query", + "ast_id_map_shim", + "parse_macro_expansion_shim", + "macro_arg_shim", + "decl_macro_expander_shim", + "crate_local_def_map", + "proc_macros_for_crate_shim", + "file_item_tree_query", + "ast_id_map_shim", + "parse_shim", + "real_span_map_shim", + "macro_def_shim", + "macro_def_shim", + "file_item_tree_query", + "ast_id_map_shim", + "parse_macro_expansion_shim", + "expand_proc_macro_shim", + "macro_arg_shim", + "proc_macro_span_shim", + ] + "#]], + expect![[r#" + [ + "parse_shim", + "ast_id_map_shim", + "file_item_tree_query", + "real_span_map_shim", + "macro_arg_shim", + "macro_arg_shim", + "decl_macro_expander_shim", + "macro_arg_shim", + ] + "#]], ); } @@ -341,19 +507,46 @@ m!(Z); "#, ); let krate = db.test_crate(); - { - let events = db.log_executed(|| { + execute_assert_events( + &db, + || { let crate_def_map = crate_def_map(&db, krate); let (_, module_data) = crate_def_map.modules.iter().last().unwrap(); assert_eq!(module_data.scope.resolutions().count(), 4); - }); - let n_recalculated_item_trees = - events.iter().filter(|it| it.contains("file_item_tree_query")).count(); - assert_eq!(n_recalculated_item_trees, 6); - let n_reparsed_macros = - events.iter().filter(|it| it.contains("parse_macro_expansion_shim")).count(); - assert_eq!(n_reparsed_macros, 3); - } + }, + &[("file_item_tree_query", 6), ("parse_macro_expansion_shim", 3)], + expect![[r#" + [ + "crate_local_def_map", + "file_item_tree_query", + "ast_id_map_shim", + "parse_shim", + "real_span_map_shim", + "file_item_tree_query", + "ast_id_map_shim", + "parse_shim", + "real_span_map_shim", + "file_item_tree_query", + "ast_id_map_shim", + "parse_shim", + "real_span_map_shim", + "macro_def_shim", + "file_item_tree_query", + "ast_id_map_shim", + "parse_macro_expansion_shim", + "macro_arg_shim", + "decl_macro_expander_shim", + "file_item_tree_query", + "ast_id_map_shim", + "parse_macro_expansion_shim", + "macro_arg_shim", + "file_item_tree_query", + "ast_id_map_shim", + "parse_macro_expansion_shim", + "macro_arg_shim", + ] + "#]], + ); let new_text = r#" m!(X); @@ -363,28 +556,31 @@ m!(Z); "#; db.set_file_text(pos.file_id.file_id(&db), new_text); - { - let events = db.log_executed(|| { + execute_assert_events( + &db, + || { let crate_def_map = crate_def_map(&db, krate); let (_, module_data) = crate_def_map.modules.iter().last().unwrap(); assert_eq!(module_data.scope.resolutions().count(), 4); - }); - let n_recalculated_item_trees = - events.iter().filter(|it| it.contains("file_item_tree_query")).count(); - assert_eq!(n_recalculated_item_trees, 1, "{events:#?}"); - let n_reparsed_macros = - events.iter().filter(|it| it.contains("parse_macro_expansion_shim")).count(); - assert_eq!(n_reparsed_macros, 0); - } + }, + &[("file_item_tree_query", 1), ("parse_macro_expansion_shim", 0)], + expect![[r#" + [ + "parse_shim", + "ast_id_map_shim", + "file_item_tree_query", + "real_span_map_shim", + "macro_arg_shim", + "macro_arg_shim", + "macro_arg_shim", + ] + "#]], + ); } #[test] fn item_tree_prevents_reparsing() { - // The `ItemTree` is used by both name resolution and the various queries in `adt.rs` and - // `data.rs`. After computing the `ItemTree` and deleting the parse tree, we should be able to - // run those other queries without triggering a reparse. - - let (db, pos) = TestDB::with_position( + let (mut db, pos) = TestDB::with_position( r#" pub struct S; pub union U {} @@ -399,53 +595,54 @@ pub static ST: u8 = 0; pub type Ty = (); "#, ); - let krate = db.test_crate(); - { - let events = db.log_executed(|| { + + execute_assert_events( + &db, + || { db.file_item_tree(pos.file_id.into()); - }); - let n_calculated_item_trees = - events.iter().filter(|it| it.contains("file_item_tree_query")).count(); - assert_eq!(n_calculated_item_trees, 1, "{events:#?}"); - let n_parsed_files = events.iter().filter(|it| it.contains("parse")).count(); - assert_eq!(n_parsed_files, 1, "{events:#?}"); - } + }, + &[("file_item_tree_query", 1), ("parse", 1)], + expect![[r#" + [ + "file_item_tree_query", + "ast_id_map_shim", + "parse_shim", + "real_span_map_shim", + ] + "#]], + ); - // FIXME(salsa-transition): bring this back - // base_db::ParseQuery.in_db(&db).purge(); + let file_id = pos.file_id.file_id(&db); + let file_text = db.file_text(file_id).text(&db); + db.set_file_text(file_id, &format!("{file_text}\n")); - { - let events = db.log_executed(|| { - let crate_def_map = crate_def_map(&db, krate); - let (_, module_data) = crate_def_map.modules.iter().last().unwrap(); - assert_eq!(module_data.scope.resolutions().count(), 8); - assert_eq!(module_data.scope.impls().count(), 1); - - for imp in module_data.scope.impls() { - db.impl_signature(imp); - } - - for (_, res) in module_data.scope.resolutions() { - match res.values.map(|it| it.def).or(res.types.map(|it| it.def)).unwrap() { - ModuleDefId::FunctionId(f) => _ = db.function_signature(f), - ModuleDefId::AdtId(adt) => match adt { - AdtId::StructId(it) => _ = db.struct_signature(it), - AdtId::UnionId(it) => _ = db.union_signature(it), - AdtId::EnumId(it) => _ = db.enum_signature(it), - }, - ModuleDefId::ConstId(it) => _ = db.const_signature(it), - ModuleDefId::StaticId(it) => _ = db.static_signature(it), - ModuleDefId::TraitId(it) => _ = db.trait_signature(it), - ModuleDefId::TraitAliasId(it) => _ = db.trait_alias_signature(it), - ModuleDefId::TypeAliasId(it) => _ = db.type_alias_signature(it), - ModuleDefId::EnumVariantId(_) - | ModuleDefId::ModuleId(_) - | ModuleDefId::MacroId(_) - | ModuleDefId::BuiltinType(_) => unreachable!(), - } - } - }); - let n_reparsed_files = events.iter().filter(|it| it.contains("parse(")).count(); - assert_eq!(n_reparsed_files, 0, "{events:?}"); - } + execute_assert_events( + &db, + || { + db.file_item_tree(pos.file_id.into()); + }, + &[("file_item_tree_query", 1), ("parse", 1)], + expect![[r#" + [ + "parse_shim", + "ast_id_map_shim", + "file_item_tree_query", + "real_span_map_shim", + ] + "#]], + ); +} + +fn execute_assert_events( + db: &TestDB, + f: impl FnOnce(), + required: &[(&str, usize)], + expect: Expect, +) { + let events = db.log_executed(f); + for (event, count) in required { + let n = events.iter().filter(|it| it.contains(event)).count(); + assert_eq!(n, *count, "Expected {event} to be executed {count} times, but only got {n}"); + } + expect.assert_debug_eq(&events); } diff --git a/crates/hir-ty/src/tests/incremental.rs b/crates/hir-ty/src/tests/incremental.rs index 74f6bbb030..b45d8babd4 100644 --- a/crates/hir-ty/src/tests/incremental.rs +++ b/crates/hir-ty/src/tests/incremental.rs @@ -1,4 +1,5 @@ use base_db::SourceDatabase; +use expect_test::Expect; use hir_def::{DefWithBodyId, ModuleDefId}; use test_fixture::WithFixture; @@ -15,8 +16,9 @@ fn foo() -> i32 { $01 + 1 }", ); - { - let events = db.log_executed(|| { + execute_assert_events( + &db, + || { let module = db.module_for_file(pos.file_id.file_id(&db)); let crate_def_map = module.def_map(&db); visit_module(&db, crate_def_map, module.local_id, &mut |def| { @@ -24,9 +26,31 @@ fn foo() -> i32 { db.infer(it.into()); } }); - }); - assert!(format!("{events:?}").contains("infer_shim")) - } + }, + &[("infer_shim", 1)], + expect_test::expect![[r#" + [ + "source_root_crates_shim", + "crate_local_def_map", + "file_item_tree_query", + "ast_id_map_shim", + "parse_shim", + "real_span_map_shim", + "infer_shim", + "function_signature_shim", + "function_signature_with_source_map_shim", + "attrs_shim", + "body_shim", + "body_with_source_map_shim", + "trait_environment_shim", + "return_type_impl_traits_shim", + "expr_scopes_shim", + "lang_item", + "crate_lang_items", + "lang_item", + ] + "#]], + ); let new_text = " fn foo() -> i32 { @@ -37,8 +61,9 @@ fn foo() -> i32 { db.set_file_text(pos.file_id.file_id(&db), new_text); - { - let events = db.log_executed(|| { + execute_assert_events( + &db, + || { let module = db.module_for_file(pos.file_id.file_id(&db)); let crate_def_map = module.def_map(&db); visit_module(&db, crate_def_map, module.local_id, &mut |def| { @@ -46,9 +71,22 @@ fn foo() -> i32 { db.infer(it.into()); } }); - }); - assert!(!format!("{events:?}").contains("infer_shim"), "{events:#?}") - } + }, + &[("infer_shim", 0)], + expect_test::expect![[r#" + [ + "parse_shim", + "ast_id_map_shim", + "file_item_tree_query", + "real_span_map_shim", + "attrs_shim", + "function_signature_with_source_map_shim", + "function_signature_shim", + "body_with_source_map_shim", + "body_shim", + ] + "#]], + ); } #[test] @@ -66,8 +104,9 @@ fn baz() -> i32 { 1 + 1 }", ); - { - let events = db.log_executed(|| { + execute_assert_events( + &db, + || { let module = db.module_for_file(pos.file_id.file_id(&db)); let crate_def_map = module.def_map(&db); visit_module(&db, crate_def_map, module.local_id, &mut |def| { @@ -75,9 +114,49 @@ fn baz() -> i32 { db.infer(it.into()); } }); - }); - assert!(format!("{events:?}").contains("infer_shim")) - } + }, + &[("infer_shim", 3)], + expect_test::expect![[r#" + [ + "source_root_crates_shim", + "crate_local_def_map", + "file_item_tree_query", + "ast_id_map_shim", + "parse_shim", + "real_span_map_shim", + "infer_shim", + "function_signature_shim", + "function_signature_with_source_map_shim", + "attrs_shim", + "body_shim", + "body_with_source_map_shim", + "trait_environment_shim", + "return_type_impl_traits_shim", + "expr_scopes_shim", + "lang_item", + "crate_lang_items", + "attrs_shim", + "attrs_shim", + "lang_item", + "infer_shim", + "function_signature_shim", + "function_signature_with_source_map_shim", + "body_shim", + "body_with_source_map_shim", + "trait_environment_shim", + "return_type_impl_traits_shim", + "expr_scopes_shim", + "infer_shim", + "function_signature_shim", + "function_signature_with_source_map_shim", + "body_shim", + "body_with_source_map_shim", + "trait_environment_shim", + "return_type_impl_traits_shim", + "expr_scopes_shim", + ] + "#]], + ); let new_text = " fn foo() -> f32 { @@ -93,8 +172,9 @@ fn baz() -> i32 { db.set_file_text(pos.file_id.file_id(&db), new_text); - { - let events = db.log_executed(|| { + execute_assert_events( + &db, + || { let module = db.module_for_file(pos.file_id.file_id(&db)); let crate_def_map = module.def_map(&db); visit_module(&db, crate_def_map, module.local_id, &mut |def| { @@ -102,9 +182,34 @@ fn baz() -> i32 { db.infer(it.into()); } }); - }); - assert_eq!(format!("{events:?}").matches("infer_shim").count(), 1, "{events:#?}") - } + }, + &[("infer_shim", 1)], + expect_test::expect![[r#" + [ + "parse_shim", + "ast_id_map_shim", + "file_item_tree_query", + "real_span_map_shim", + "attrs_shim", + "function_signature_with_source_map_shim", + "function_signature_shim", + "body_with_source_map_shim", + "body_shim", + "attrs_shim", + "attrs_shim", + "function_signature_with_source_map_shim", + "function_signature_shim", + "body_with_source_map_shim", + "body_shim", + "infer_shim", + "expr_scopes_shim", + "function_signature_with_source_map_shim", + "function_signature_shim", + "body_with_source_map_shim", + "body_shim", + ] + "#]], + ); } #[test] @@ -121,14 +226,26 @@ fn bar() -> f32 { } $0", ); - { - let events = db.log_executed(|| { + execute_assert_events( + &db, + || { let module = db.module_for_file(pos.file_id.file_id(&db)); let _crate_def_map = module.def_map(&db); db.trait_impls_in_crate(module.krate()); - }); - assert!(format!("{events:?}").contains("trait_impls_in_crate_shim")) - } + }, + &[("trait_impls_in_crate_shim", 1)], + expect_test::expect![[r#" + [ + "source_root_crates_shim", + "crate_local_def_map", + "file_item_tree_query", + "ast_id_map_shim", + "parse_shim", + "real_span_map_shim", + "trait_impls_in_crate_shim", + ] + "#]], + ); let new_text = " fn foo() -> i32 { @@ -146,24 +263,25 @@ pub struct NewStruct { db.set_file_text(pos.file_id.file_id(&db), new_text); - { - let actual = db.log_executed(|| { + execute_assert_events( + &db, + || { let module = db.module_for_file(pos.file_id.file_id(&db)); let _crate_def_map = module.def_map(&db); db.trait_impls_in_crate(module.krate()); - }); - - let expected = vec![ - "parse_shim".to_owned(), - "ast_id_map_shim".to_owned(), - "file_item_tree_query".to_owned(), - "real_span_map_shim".to_owned(), - "crate_local_def_map".to_owned(), - "trait_impls_in_crate_shim".to_owned(), - ]; - - assert_eq!(expected, actual); - } + }, + &[("trait_impls_in_crate_shim", 1)], + expect_test::expect![[r#" + [ + "parse_shim", + "ast_id_map_shim", + "file_item_tree_query", + "real_span_map_shim", + "crate_local_def_map", + "trait_impls_in_crate_shim", + ] + "#]], + ); } #[test] @@ -180,14 +298,26 @@ fn bar() -> f32 { } $0", ); - { - let events = db.log_executed(|| { + execute_assert_events( + &db, + || { let module = db.module_for_file(pos.file_id.file_id(&db)); let _crate_def_map = module.def_map(&db); db.trait_impls_in_crate(module.krate()); - }); - assert!(format!("{events:?}").contains("trait_impls_in_crate_shim")) - } + }, + &[("trait_impls_in_crate_shim", 1)], + expect_test::expect![[r#" + [ + "source_root_crates_shim", + "crate_local_def_map", + "file_item_tree_query", + "ast_id_map_shim", + "parse_shim", + "real_span_map_shim", + "trait_impls_in_crate_shim", + ] + "#]], + ); let new_text = " fn foo() -> i32 { @@ -206,24 +336,25 @@ pub enum SomeEnum { db.set_file_text(pos.file_id.file_id(&db), new_text); - { - let actual = db.log_executed(|| { + execute_assert_events( + &db, + || { let module = db.module_for_file(pos.file_id.file_id(&db)); let _crate_def_map = module.def_map(&db); db.trait_impls_in_crate(module.krate()); - }); - - let expected = vec![ - "parse_shim".to_owned(), - "ast_id_map_shim".to_owned(), - "file_item_tree_query".to_owned(), - "real_span_map_shim".to_owned(), - "crate_local_def_map".to_owned(), - "trait_impls_in_crate_shim".to_owned(), - ]; - - assert_eq!(expected, actual); - } + }, + &[("trait_impls_in_crate_shim", 1)], + expect_test::expect![[r#" + [ + "parse_shim", + "ast_id_map_shim", + "file_item_tree_query", + "real_span_map_shim", + "crate_local_def_map", + "trait_impls_in_crate_shim", + ] + "#]], + ); } #[test] @@ -240,14 +371,26 @@ fn bar() -> f32 { } $0", ); - { - let events = db.log_executed(|| { + execute_assert_events( + &db, + || { let module = db.module_for_file(pos.file_id.file_id(&db)); let _crate_def_map = module.def_map(&db); db.trait_impls_in_crate(module.krate()); - }); - assert!(format!("{events:?}").contains("trait_impls_in_crate_shim")) - } + }, + &[("trait_impls_in_crate_shim", 1)], + expect_test::expect![[r#" + [ + "source_root_crates_shim", + "crate_local_def_map", + "file_item_tree_query", + "ast_id_map_shim", + "parse_shim", + "real_span_map_shim", + "trait_impls_in_crate_shim", + ] + "#]], + ); let new_text = " use std::collections::HashMap; @@ -263,24 +406,25 @@ fn bar() -> f32 { db.set_file_text(pos.file_id.file_id(&db), new_text); - { - let actual = db.log_executed(|| { + execute_assert_events( + &db, + || { let module = db.module_for_file(pos.file_id.file_id(&db)); let _crate_def_map = module.def_map(&db); db.trait_impls_in_crate(module.krate()); - }); - - let expected = vec![ - "parse_shim".to_owned(), - "ast_id_map_shim".to_owned(), - "file_item_tree_query".to_owned(), - "real_span_map_shim".to_owned(), - "crate_local_def_map".to_owned(), - "trait_impls_in_crate_shim".to_owned(), - ]; - - assert_eq!(expected, actual); - } + }, + &[("trait_impls_in_crate_shim", 1)], + expect_test::expect![[r#" + [ + "parse_shim", + "ast_id_map_shim", + "file_item_tree_query", + "real_span_map_shim", + "crate_local_def_map", + "trait_impls_in_crate_shim", + ] + "#]], + ); } #[test] @@ -301,14 +445,26 @@ pub struct SomeStruct { } $0", ); - { - let events = db.log_executed(|| { + execute_assert_events( + &db, + || { let module = db.module_for_file(pos.file_id.file_id(&db)); let _crate_def_map = module.def_map(&db); db.trait_impls_in_crate(module.krate()); - }); - assert!(format!("{events:?}").contains("trait_impls_in_crate_shim")) - } + }, + &[("trait_impls_in_crate_shim", 1)], + expect_test::expect![[r#" + [ + "source_root_crates_shim", + "crate_local_def_map", + "file_item_tree_query", + "ast_id_map_shim", + "parse_shim", + "real_span_map_shim", + "trait_impls_in_crate_shim", + ] + "#]], + ); let new_text = " fn foo() -> i32 { @@ -332,33 +488,34 @@ impl SomeStruct { db.set_file_text(pos.file_id.file_id(&db), new_text); - { - let actual = db.log_executed(|| { + execute_assert_events( + &db, + || { let module = db.module_for_file(pos.file_id.file_id(&db)); let _crate_def_map = module.def_map(&db); db.trait_impls_in_crate(module.krate()); - }); - - let expected = vec![ - "parse_shim".to_owned(), - "ast_id_map_shim".to_owned(), - "file_item_tree_query".to_owned(), - "real_span_map_shim".to_owned(), - "crate_local_def_map".to_owned(), - "trait_impls_in_crate_shim".to_owned(), - "attrs_shim".to_owned(), - "impl_trait_with_diagnostics_shim".to_owned(), - "impl_signature_shim".to_owned(), - "impl_signature_with_source_map_shim".to_owned(), - "impl_self_ty_with_diagnostics_shim".to_owned(), - "struct_signature_shim".to_owned(), - "struct_signature_with_source_map_shim".to_owned(), - "attrs_shim".to_owned(), - "type_for_adt_tracked".to_owned(), - ]; - - assert_eq!(expected, actual); - } + }, + &[("trait_impls_in_crate_shim", 1)], + expect_test::expect![[r#" + [ + "parse_shim", + "ast_id_map_shim", + "file_item_tree_query", + "real_span_map_shim", + "crate_local_def_map", + "trait_impls_in_crate_shim", + "attrs_shim", + "impl_trait_with_diagnostics_shim", + "impl_signature_shim", + "impl_signature_with_source_map_shim", + "impl_self_ty_with_diagnostics_shim", + "struct_signature_shim", + "struct_signature_with_source_map_shim", + "attrs_shim", + "type_for_adt_tracked", + ] + "#]], + ); } #[test] @@ -380,8 +537,9 @@ fn main() { }", ); - { - let events = db.log_executed(|| { + execute_assert_events( + &db, + || { let module = db.module_for_file(file_id.file_id(&db)); let crate_def_map = module.def_map(&db); let mut defs: Vec = vec![]; @@ -399,9 +557,73 @@ fn main() { for def in defs { let _inference_result = db.infer(def); } - }); - assert!(format!("{events:?}").contains("trait_solve_shim")) - } + }, + &[("trait_solve_shim", 2)], + expect_test::expect![[r#" + [ + "source_root_crates_shim", + "crate_local_def_map", + "file_item_tree_query", + "ast_id_map_shim", + "parse_shim", + "real_span_map_shim", + "trait_items_with_diagnostics_shim", + "body_shim", + "body_with_source_map_shim", + "attrs_shim", + "impl_items_with_diagnostics_shim", + "infer_shim", + "trait_signature_shim", + "trait_signature_with_source_map_shim", + "attrs_shim", + "function_signature_shim", + "function_signature_with_source_map_shim", + "attrs_shim", + "body_shim", + "body_with_source_map_shim", + "trait_environment_shim", + "lang_item", + "crate_lang_items", + "attrs_shim", + "attrs_shim", + "return_type_impl_traits_shim", + "infer_shim", + "function_signature_shim", + "function_signature_with_source_map_shim", + "trait_environment_shim", + "expr_scopes_shim", + "struct_signature_shim", + "struct_signature_with_source_map_shim", + "generic_predicates_shim", + "value_ty_shim", + "variant_fields_shim", + "variant_fields_with_source_map_shim", + "lang_item", + "inherent_impls_in_crate_shim", + "impl_signature_shim", + "impl_signature_with_source_map_shim", + "callable_item_signature_shim", + "adt_variance_shim", + "variances_of_shim", + "trait_solve_shim", + "trait_datum_shim", + "generic_predicates_shim", + "adt_datum_shim", + "trait_impls_in_deps_shim", + "trait_impls_in_crate_shim", + "impl_trait_with_diagnostics_shim", + "impl_self_ty_with_diagnostics_shim", + "type_for_adt_tracked", + "impl_datum_shim", + "generic_predicates_shim", + "program_clauses_for_chalk_env_shim", + "value_ty_shim", + "generic_predicates_shim", + "trait_solve_shim", + "lang_item", + ] + "#]], + ); let new_text = " //- /main.rs crate:main @@ -422,8 +644,9 @@ fn main() { db.set_file_text(file_id.file_id(&db), new_text); - { - let events = db.log_executed(|| { + execute_assert_events( + &db, + || { let module = db.module_for_file(file_id.file_id(&db)); let crate_def_map = module.def_map(&db); let mut defs: Vec = vec![]; @@ -442,7 +665,66 @@ fn main() { for def in defs { let _inference_result = db.infer(def); } - }); - assert!(!format!("{events:?}").contains("trait_solve_shim")) - } + }, + &[("trait_solve_shim", 0)], + expect_test::expect![[r#" + [ + "parse_shim", + "ast_id_map_shim", + "file_item_tree_query", + "real_span_map_shim", + "crate_local_def_map", + "trait_items_with_diagnostics_shim", + "body_with_source_map_shim", + "attrs_shim", + "body_shim", + "impl_items_with_diagnostics_shim", + "infer_shim", + "attrs_shim", + "trait_signature_with_source_map_shim", + "attrs_shim", + "function_signature_with_source_map_shim", + "function_signature_shim", + "body_with_source_map_shim", + "body_shim", + "trait_environment_shim", + "crate_lang_items", + "attrs_shim", + "attrs_shim", + "attrs_shim", + "return_type_impl_traits_shim", + "infer_shim", + "function_signature_with_source_map_shim", + "trait_environment_shim", + "expr_scopes_shim", + "struct_signature_with_source_map_shim", + "generic_predicates_shim", + "variant_fields_with_source_map_shim", + "inherent_impls_in_crate_shim", + "impl_signature_with_source_map_shim", + "impl_signature_shim", + "callable_item_signature_shim", + "generic_predicates_shim", + "trait_impls_in_crate_shim", + "impl_trait_with_diagnostics_shim", + "impl_self_ty_with_diagnostics_shim", + "generic_predicates_shim", + "generic_predicates_shim", + ] + "#]], + ); +} + +fn execute_assert_events( + db: &TestDB, + f: impl FnOnce(), + required: &[(&str, usize)], + expect: Expect, +) { + let events = db.log_executed(f); + for (event, count) in required { + let n = events.iter().filter(|it| it.contains(event)).count(); + assert_eq!(n, *count, "Expected {event} to be executed {count} times, but only got {n}"); + } + expect.assert_debug_eq(&events); } From aa2d23442641335669062f14ef64912549754d05 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 15 Jun 2025 08:43:22 +0200 Subject: [PATCH 47/56] Idiomatic salsa use for enum variants query --- Cargo.toml | 4 +++- crates/hir-def/src/db.rs | 20 +++---------------- crates/hir-def/src/find_path.rs | 2 +- crates/hir-def/src/lang_item.rs | 2 +- crates/hir-def/src/lib.rs | 18 ++++++++++++++++- crates/hir-def/src/nameres/collector.rs | 5 ++--- crates/hir-def/src/nameres/path_resolution.rs | 4 ++-- .../hir-def/src/nameres/tests/incremental.rs | 5 ++--- crates/hir-def/src/signatures.rs | 15 +++++++------- crates/hir-ty/src/chalk_db.rs | 4 ++-- crates/hir-ty/src/consteval.rs | 2 +- crates/hir-ty/src/diagnostics/decl_check.rs | 2 +- crates/hir-ty/src/diagnostics/expr.rs | 2 +- crates/hir-ty/src/diagnostics/match_check.rs | 2 +- .../diagnostics/match_check/pat_analysis.rs | 4 ++-- crates/hir-ty/src/display.rs | 4 ++-- crates/hir-ty/src/drop.rs | 4 ++-- crates/hir-ty/src/infer.rs | 4 ++-- crates/hir-ty/src/infer/cast.rs | 2 +- crates/hir-ty/src/infer/closure.rs | 2 +- crates/hir-ty/src/infer/path.rs | 2 +- crates/hir-ty/src/inhabitedness.rs | 2 +- crates/hir-ty/src/layout/adt.rs | 4 ++-- crates/hir-ty/src/mir/eval.rs | 8 ++++---- crates/hir-ty/src/mir/lower.rs | 6 +++--- crates/hir-ty/src/mir/pretty.rs | 5 +++-- crates/hir-ty/src/tests.rs | 2 +- crates/hir-ty/src/tls.rs | 2 +- crates/hir-ty/src/utils.rs | 6 +++--- crates/hir-ty/src/variance.rs | 2 +- crates/hir/src/lib.rs | 8 ++++---- crates/hir/src/semantics/child_by_source.rs | 2 +- crates/hir/src/source_analyzer.rs | 2 +- 33 files changed, 81 insertions(+), 77 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c5f061cad7..c791d741b0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -134,7 +134,9 @@ pulldown-cmark-to-cmark = "10.0.4" pulldown-cmark = { version = "0.9.6", default-features = false } rayon = "1.10.0" rowan = "=0.15.15" -salsa = { version = "0.22.0", default-features = false, features = ["rayon","salsa_unstable"] } +# Ideally we'd not enable the macros feature but unfortunately the `tracked` attribute does not work +# on impls without it +salsa = { version = "0.22.0", default-features = true, features = ["rayon","salsa_unstable", "macros"] } salsa-macros = "0.22.0" semver = "1.0.26" serde = { version = "1.0.219" } diff --git a/crates/hir-def/src/db.rs b/crates/hir-def/src/db.rs index f024f04efe..2fc79c3809 100644 --- a/crates/hir-def/src/db.rs +++ b/crates/hir-def/src/db.rs @@ -8,7 +8,6 @@ use hir_expand::{ use intern::{Symbol, sym}; use la_arena::ArenaMap; use syntax::{AstPtr, ast}; -use thin_vec::ThinVec; use triomphe::Arc; use crate::{ @@ -32,9 +31,9 @@ use crate::{ diagnostics::DefDiagnostics, }, signatures::{ - ConstSignature, EnumSignature, EnumVariants, FunctionSignature, ImplSignature, - InactiveEnumVariantCode, StaticSignature, StructSignature, TraitAliasSignature, - TraitSignature, TypeAliasSignature, UnionSignature, VariantFields, + ConstSignature, EnumSignature, FunctionSignature, ImplSignature, StaticSignature, + StructSignature, TraitAliasSignature, TraitSignature, TypeAliasSignature, UnionSignature, + VariantFields, }, tt, visibility::{self, Visibility}, @@ -121,19 +120,6 @@ 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 - } - - #[salsa::invoke(EnumVariants::enum_variants_query)] - fn enum_variants_with_diagnostics( - &self, - id: EnumId, - ) -> (Arc, Option>>); - #[salsa::transparent] #[salsa::invoke(ImplItems::impl_items_query)] fn impl_items(&self, e: ImplId) -> Arc; diff --git a/crates/hir-def/src/find_path.rs b/crates/hir-def/src/find_path.rs index bb75621c7e..6ebc0d8dfd 100644 --- a/crates/hir-def/src/find_path.rs +++ b/crates/hir-def/src/find_path.rs @@ -137,7 +137,7 @@ fn find_path_inner(ctx: &FindPathCtx<'_>, item: ItemInNs, max_len: usize) -> Opt let loc = variant.lookup(ctx.db); if let Some(mut path) = find_path_inner(ctx, ItemInNs::Types(loc.parent.into()), max_len) { path.push_segment( - ctx.db.enum_variants(loc.parent).variants[loc.index as usize].1.clone(), + loc.parent.enum_variants(ctx.db).variants[loc.index as usize].1.clone(), ); return Some(path); } diff --git a/crates/hir-def/src/lang_item.rs b/crates/hir-def/src/lang_item.rs index 8f071cd953..c0e30ac795 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, _, _)| { + e.enum_variants(db).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 e7ab2b4d77..be5bb57ade 100644 --- a/crates/hir-def/src/lib.rs +++ b/crates/hir-def/src/lib.rs @@ -51,6 +51,7 @@ pub mod visibility; use intern::{Interned, sym}; pub use rustc_abi as layout; +use thin_vec::ThinVec; use triomphe::Arc; pub use crate::signatures::LocalFieldId; @@ -88,7 +89,7 @@ use crate::{ db::DefDatabase, hir::generics::{LocalLifetimeParamId, LocalTypeOrConstParamId}, nameres::{LocalDefMap, block_def_map, crate_def_map, crate_local_def_map}, - signatures::VariantFields, + signatures::{EnumVariants, InactiveEnumVariantCode, VariantFields}, }; type FxIndexMap = indexmap::IndexMap; @@ -253,6 +254,21 @@ impl_intern!(UnionId, UnionLoc, intern_union, lookup_intern_union); pub type EnumLoc = ItemLoc; impl_intern!(EnumId, EnumLoc, intern_enum, lookup_intern_enum); +impl EnumId { + #[inline] + pub fn enum_variants(self, db: &dyn DefDatabase) -> &EnumVariants { + &self.enum_variants_with_diagnostics(db).0 + } + + #[inline] + pub fn enum_variants_with_diagnostics( + self, + db: &dyn DefDatabase, + ) -> &(EnumVariants, Option>) { + EnumVariants::of(db, self) + } +} + type ConstLoc = AssocItemLoc; impl_intern!(ConstId, ConstLoc, intern_const, lookup_intern_const); diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index 29f94ac2dc..3a2faae366 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -995,9 +995,8 @@ impl<'db> DefCollector<'db> { Some(ModuleDefId::AdtId(AdtId::EnumId(e))) => { cov_mark::hit!(glob_enum); // glob import from enum => just import all the variants - let resolutions = self - .db - .enum_variants(e) + let resolutions = e + .enum_variants(self.db) .variants .iter() .map(|&(variant, ref name, _)| { diff --git a/crates/hir-def/src/nameres/path_resolution.rs b/crates/hir-def/src/nameres/path_resolution.rs index e0e32a7773..ca39173d47 100644 --- a/crates/hir-def/src/nameres/path_resolution.rs +++ b/crates/hir-def/src/nameres/path_resolution.rs @@ -528,8 +528,8 @@ impl DefMap { // enum variant cov_mark::hit!(can_import_enum_variant); - let res = db - .enum_variants(e) + let res = e + .enum_variants(db) .variants .iter() .find(|(_, name, _)| name == segment) diff --git a/crates/hir-def/src/nameres/tests/incremental.rs b/crates/hir-def/src/nameres/tests/incremental.rs index 858aa055ed..77e706caed 100644 --- a/crates/hir-def/src/nameres/tests/incremental.rs +++ b/crates/hir-def/src/nameres/tests/incremental.rs @@ -172,8 +172,7 @@ fn no() {} "ast_id_map_shim", "parse_shim", "real_span_map_shim", - "enum_variants_shim", - "enum_variants_with_diagnostics_shim", + "of_", ] "#]], expect![[r#" @@ -182,7 +181,7 @@ fn no() {} "ast_id_map_shim", "file_item_tree_query", "real_span_map_shim", - "enum_variants_with_diagnostics_shim", + "of_", ] "#]], ); diff --git a/crates/hir-def/src/signatures.rs b/crates/hir-def/src/signatures.rs index b7d29f54d0..c808079011 100644 --- a/crates/hir-def/src/signatures.rs +++ b/crates/hir-def/src/signatures.rs @@ -884,11 +884,13 @@ pub struct EnumVariants { pub variants: Box<[(EnumVariantId, Name, FieldsShape)]>, } +#[salsa::tracked] impl EnumVariants { - pub(crate) fn enum_variants_query( + #[salsa::tracked(returns(ref))] + pub(crate) fn of( db: &dyn DefDatabase, e: EnumId, - ) -> (Arc, Option>>) { + ) -> (EnumVariants, Option>) { let loc = e.lookup(db); let source = loc.source(db); let ast_id_map = db.ast_id_map(source.file_id); @@ -898,7 +900,7 @@ impl EnumVariants { let cfg_options = loc.container.krate.cfg_options(db); let mut index = 0; let Some(variants) = source.value.variant_list() else { - return (Arc::new(EnumVariants { variants: Box::default() }), None); + return (EnumVariants { variants: Box::default() }, None); }; let variants = variants .variants() @@ -926,12 +928,11 @@ impl EnumVariants { }) .collect(); - ( - Arc::new(EnumVariants { variants }), - diagnostics.is_empty().not().then(|| Arc::new(diagnostics)), - ) + (EnumVariants { variants }, diagnostics.is_empty().not().then_some(diagnostics)) } +} +impl EnumVariants { pub fn variant(&self, name: &Name) -> Option { self.variants.iter().find_map(|(v, n, _)| if n == name { Some(*v) } else { None }) } diff --git a/crates/hir-ty/src/chalk_db.rs b/crates/hir-ty/src/chalk_db.rs index f658e23665..cf43924513 100644 --- a/crates/hir-ty/src/chalk_db.rs +++ b/crates/hir-ty/src/chalk_db.rs @@ -823,8 +823,8 @@ pub(crate) fn adt_datum_query( (rust_ir::AdtKind::Struct, vec![variant_id_to_fields(id.into())]) } hir_def::AdtId::EnumId(id) => { - let variants = db - .enum_variants(id) + let variants = id + .enum_variants(db) .variants .iter() .map(|&(variant_id, _, _)| variant_id_to_fields(variant_id.into())) diff --git a/crates/hir-ty/src/consteval.rs b/crates/hir-ty/src/consteval.rs index f903b06d65..24530a5f67 100644 --- a/crates/hir-ty/src/consteval.rs +++ b/crates/hir-ty/src/consteval.rs @@ -286,7 +286,7 @@ pub(crate) fn const_eval_discriminant_variant( let value = match prev_idx { Some(prev_idx) => { 1 + db.const_eval_discriminant( - db.enum_variants(loc.parent).variants[prev_idx as usize].0, + loc.parent.enum_variants(db).variants[prev_idx as usize].0, )? } _ => 0, diff --git a/crates/hir-ty/src/diagnostics/decl_check.rs b/crates/hir-ty/src/diagnostics/decl_check.rs index fae129fddb..1873f12fb7 100644 --- a/crates/hir-ty/src/diagnostics/decl_check.rs +++ b/crates/hir-ty/src/diagnostics/decl_check.rs @@ -395,7 +395,7 @@ impl<'a> DeclValidator<'a> { /// Check incorrect names for enum variants. fn validate_enum_variants(&mut self, enum_id: EnumId) { - let data = self.db.enum_variants(enum_id); + let data = enum_id.enum_variants(self.db); for (variant_id, _, _) in data.variants.iter() { self.validate_enum_variant_fields(*variant_id); diff --git a/crates/hir-ty/src/diagnostics/expr.rs b/crates/hir-ty/src/diagnostics/expr.rs index 9eb7ffe1c7..df2eb410b9 100644 --- a/crates/hir-ty/src/diagnostics/expr.rs +++ b/crates/hir-ty/src/diagnostics/expr.rs @@ -642,7 +642,7 @@ fn missing_match_arms<'p>( } let non_empty_enum = match scrut_ty.as_adt() { - Some((AdtId::EnumId(e), _)) => !cx.db.enum_variants(e).variants.is_empty(), + Some((AdtId::EnumId(e), _)) => !e.enum_variants(cx.db).variants.is_empty(), _ => false, }; let display_target = DisplayTarget::from_crate(cx.db, krate); diff --git a/crates/hir-ty/src/diagnostics/match_check.rs b/crates/hir-ty/src/diagnostics/match_check.rs index 7df22a45cb..916876d4ac 100644 --- a/crates/hir-ty/src/diagnostics/match_check.rs +++ b/crates/hir-ty/src/diagnostics/match_check.rs @@ -328,7 +328,7 @@ impl HirDisplay for Pat { write!( f, "{}", - f.db.enum_variants(loc.parent).variants[loc.index as usize] + loc.parent.enum_variants(f.db).variants[loc.index as usize] .1 .display(f.db, f.edition()) )?; 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 0914b5aac5..2873a3e09e 100644 --- a/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs +++ b/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs @@ -50,7 +50,7 @@ impl EnumVariantContiguousIndex { } fn to_enum_variant_id(self, db: &dyn HirDatabase, eid: EnumId) -> EnumVariantId { - db.enum_variants(eid).variants[self.0].0 + eid.enum_variants(db).variants[self.0].0 } } @@ -458,7 +458,7 @@ impl PatCx for MatchCheckCtx<'_> { TyKind::Scalar(Scalar::Int(..) | Scalar::Uint(..)) => unhandled(), TyKind::Array(..) | TyKind::Slice(..) => unhandled(), &TyKind::Adt(AdtId(adt @ hir_def::AdtId::EnumId(enum_id)), ref subst) => { - let enum_data = cx.db.enum_variants(enum_id); + let enum_data = enum_id.enum_variants(cx.db); let is_declared_nonexhaustive = cx.is_foreign_non_exhaustive(adt); if enum_data.variants.is_empty() && !is_declared_nonexhaustive { diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs index f210dd8799..da21f08a1e 100644 --- a/crates/hir-ty/src/display.rs +++ b/crates/hir-ty/src/display.rs @@ -914,7 +914,7 @@ fn render_const_scalar( write!( f, "{}", - f.db.enum_variants(loc.parent).variants[loc.index as usize] + loc.parent.enum_variants(f.db).variants[loc.index as usize] .1 .display(f.db, f.edition()) )?; @@ -1208,7 +1208,7 @@ impl HirDisplay for Ty { write!( f, "{}", - db.enum_variants(loc.parent).variants[loc.index as usize] + loc.parent.enum_variants(db).variants[loc.index as usize] .1 .display(db, f.edition()) )? diff --git a/crates/hir-ty/src/drop.rs b/crates/hir-ty/src/drop.rs index b9b0f98286..5577be890d 100644 --- a/crates/hir-ty/src/drop.rs +++ b/crates/hir-ty/src/drop.rs @@ -67,8 +67,8 @@ pub(crate) fn has_drop_glue(db: &dyn HirDatabase, ty: Ty, env: Arc DropGlue::None, - AdtId::EnumId(id) => db - .enum_variants(id) + AdtId::EnumId(id) => id + .enum_variants(db) .variants .iter() .map(|&(variant, _, _)| { diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index 14eb716075..80478f1937 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -1673,7 +1673,7 @@ impl<'db> InferenceContext<'db> { // If we can resolve to an enum variant, it takes priority over associated type // of the same name. if let Some((AdtId::EnumId(id), _)) = ty.as_adt() { - let enum_data = self.db.enum_variants(id); + let enum_data = id.enum_variants(self.db); if let Some(variant) = enum_data.variant(current_segment.name) { return if remaining_segments.len() == 1 { (ty, Some(variant.into())) @@ -1792,7 +1792,7 @@ impl<'db> InferenceContext<'db> { let segment = path.segments().last().unwrap(); // this could be an enum variant or associated type if let Some((AdtId::EnumId(enum_id), _)) = ty.as_adt() { - let enum_data = self.db.enum_variants(enum_id); + let enum_data = enum_id.enum_variants(self.db); if let Some(variant) = enum_data.variant(segment) { return (ty, Some(variant.into())); } diff --git a/crates/hir-ty/src/infer/cast.rs b/crates/hir-ty/src/infer/cast.rs index 10d85792c9..8d345defdc 100644 --- a/crates/hir-ty/src/infer/cast.rs +++ b/crates/hir-ty/src/infer/cast.rs @@ -43,7 +43,7 @@ impl CastTy { let (AdtId::EnumId(id), _) = t.as_adt()? else { return None; }; - let enum_data = table.db.enum_variants(id); + let enum_data = id.enum_variants(table.db); if enum_data.is_payload_free(table.db) { Some(Self::Int(Int::CEnum)) } else { None } } TyKind::Raw(m, ty) => Some(Self::Ptr(ty.clone(), *m)), diff --git a/crates/hir-ty/src/infer/closure.rs b/crates/hir-ty/src/infer/closure.rs index bd57ca8916..d1432cacf8 100644 --- a/crates/hir-ty/src/infer/closure.rs +++ b/crates/hir-ty/src/infer/closure.rs @@ -1360,7 +1360,7 @@ impl InferenceContext<'_> { if let Some(variant) = self.result.variant_resolution_for_pat(p) { let adt = variant.adt_id(self.db); let is_multivariant = match adt { - hir_def::AdtId::EnumId(e) => self.db.enum_variants(e).variants.len() != 1, + hir_def::AdtId::EnumId(e) => e.enum_variants(self.db).variants.len() != 1, _ => false, }; if is_multivariant { diff --git a/crates/hir-ty/src/infer/path.rs b/crates/hir-ty/src/infer/path.rs index 9d4bbe5346..c327c13b66 100644 --- a/crates/hir-ty/src/infer/path.rs +++ b/crates/hir-ty/src/infer/path.rs @@ -397,7 +397,7 @@ impl InferenceContext<'_> { Some((AdtId::EnumId(e), subst)) => (e, subst), _ => return None, }; - let enum_data = self.db.enum_variants(enum_id); + let enum_data = enum_id.enum_variants(self.db); let variant = enum_data.variant(name)?; self.write_variant_resolution(id, variant.into()); Some((ValueNs::EnumVariantId(variant), subst.clone())) diff --git a/crates/hir-ty/src/inhabitedness.rs b/crates/hir-ty/src/inhabitedness.rs index 8be812d8d5..79a99321f1 100644 --- a/crates/hir-ty/src/inhabitedness.rs +++ b/crates/hir-ty/src/inhabitedness.rs @@ -113,7 +113,7 @@ impl UninhabitedFrom<'_> { AdtId::UnionId(_) => CONTINUE_OPAQUELY_INHABITED, AdtId::StructId(s) => self.visit_variant(s.into(), subst), AdtId::EnumId(e) => { - let enum_data = self.db.enum_variants(e); + let enum_data = e.enum_variants(self.db); for &(variant, _, _) in enum_data.variants.iter() { let variant_inhabitedness = self.visit_variant(variant.into(), subst); diff --git a/crates/hir-ty/src/layout/adt.rs b/crates/hir-ty/src/layout/adt.rs index a886c33d15..dff986fec3 100644 --- a/crates/hir-ty/src/layout/adt.rs +++ b/crates/hir-ty/src/layout/adt.rs @@ -56,7 +56,7 @@ pub fn layout_of_adt_query( (r, data.repr.unwrap_or_default(), false) } AdtId::EnumId(e) => { - let variants = db.enum_variants(e); + let variants = e.enum_variants(db); let r = variants .variants .iter() @@ -82,7 +82,7 @@ pub fn layout_of_adt_query( |min, max| repr_discr(dl, &repr, min, max).unwrap_or((Integer::I8, false)), variants.iter_enumerated().filter_map(|(id, _)| { let AdtId::EnumId(e) = def else { return None }; - let d = db.const_eval_discriminant(db.enum_variants(e).variants[id.0].0).ok()?; + let d = db.const_eval_discriminant(e.enum_variants(db).variants[id.0].0).ok()?; Some((id, d)) }), // FIXME: The current code for niche-filling relies on variant indices diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs index da6e4e5d8a..a8156ec375 100644 --- a/crates/hir-ty/src/mir/eval.rs +++ b/crates/hir-ty/src/mir/eval.rs @@ -1631,7 +1631,7 @@ impl Evaluator<'_> { Variants::Empty => unreachable!(), Variants::Single { index } => { let r = - self.const_eval_discriminant(self.db.enum_variants(e).variants[index.0].0)?; + self.const_eval_discriminant(e.enum_variants(self.db).variants[index.0].0)?; Ok(r) } Variants::Multiple { tag, tag_encoding, variants, .. } => { @@ -1656,7 +1656,7 @@ impl Evaluator<'_> { .unwrap_or(*untagged_variant) .0; let result = - self.const_eval_discriminant(self.db.enum_variants(e).variants[idx].0)?; + self.const_eval_discriminant(e.enum_variants(self.db).variants[idx].0)?; Ok(result) } } @@ -2775,8 +2775,8 @@ impl Evaluator<'_> { let name = format!( "{}::{}", self.db.enum_signature(loc.parent).name.display(db, edition), - self.db - .enum_variants(loc.parent) + loc.parent + .enum_variants(self.db) .variant_name_by_id(variant) .unwrap() .display(db, edition), diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs index ef1f215500..71e038b92f 100644 --- a/crates/hir-ty/src/mir/lower.rs +++ b/crates/hir-ty/src/mir/lower.rs @@ -1925,8 +1925,8 @@ impl<'ctx> MirLowerCtx<'ctx> { let name = format!( "{}::{}", self.db.enum_signature(loc.parent).name.display(db, edition), - self.db - .enum_variants(loc.parent) + loc.parent + .enum_variants(self.db) .variant_name_by_id(variant) .unwrap() .display(db, edition), @@ -2155,7 +2155,7 @@ pub fn mir_body_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Result { let loc = it.lookup(db); - db.enum_variants(loc.parent).variants[loc.index as usize] + loc.parent.enum_variants(db).variants[loc.index as usize] .1 .display(db, edition) .to_string() diff --git a/crates/hir-ty/src/mir/pretty.rs b/crates/hir-ty/src/mir/pretty.rs index 91dc2627d1..8764e48b53 100644 --- a/crates/hir-ty/src/mir/pretty.rs +++ b/crates/hir-ty/src/mir/pretty.rs @@ -68,7 +68,8 @@ impl MirBody { this, "enum {}::{} = ", db.enum_signature(loc.parent).name.display(db, edition), - db.enum_variants(loc.parent) + loc.parent + .enum_variants(db) .variant_name_by_id(id) .unwrap() .display(db, edition), @@ -335,7 +336,7 @@ impl<'a> MirPrettyCtx<'a> { w!( this, " as {}).{}", - this.db.enum_variants(loc.parent).variants[loc.index as usize] + loc.parent.enum_variants(this.db).variants[loc.index as usize] .1 .display(this.db, this.display_target.edition), name.display(this.db, this.display_target.edition) diff --git a/crates/hir-ty/src/tests.rs b/crates/hir-ty/src/tests.rs index 48af7b2e32..f2812570ed 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, _, _)| { + it.enum_variants(db).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/tls.rs b/crates/hir-ty/src/tls.rs index f5911e2161..f53409af2b 100644 --- a/crates/hir-ty/src/tls.rs +++ b/crates/hir-ty/src/tls.rs @@ -109,7 +109,7 @@ impl DebugContext<'_> { CallableDefId::StructId(s) => self.0.struct_signature(s).name.clone(), CallableDefId::EnumVariantId(e) => { let loc = e.lookup(self.0); - self.0.enum_variants(loc.parent).variants[loc.index as usize].1.clone() + loc.parent.enum_variants(self.0).variants[loc.index as usize].1.clone() } }; match def { diff --git a/crates/hir-ty/src/utils.rs b/crates/hir-ty/src/utils.rs index f797e60b05..867c7ea087 100644 --- a/crates/hir-ty/src/utils.rs +++ b/crates/hir-ty/src/utils.rs @@ -355,7 +355,7 @@ pub(crate) fn detect_variant_from_bytes<'a>( let (var_id, var_layout) = match &layout.variants { hir_def::layout::Variants::Empty => unreachable!(), hir_def::layout::Variants::Single { index } => { - (db.enum_variants(e).variants[index.0].0, layout) + (e.enum_variants(db).variants[index.0].0, layout) } hir_def::layout::Variants::Multiple { tag, tag_encoding, variants, .. } => { let size = tag.size(target_data_layout).bytes_usize(); @@ -365,7 +365,7 @@ pub(crate) fn detect_variant_from_bytes<'a>( TagEncoding::Direct => { let (var_idx, layout) = variants.iter_enumerated().find_map(|(var_idx, v)| { - let def = db.enum_variants(e).variants[var_idx.0].0; + let def = e.enum_variants(db).variants[var_idx.0].0; (db.const_eval_discriminant(def) == Ok(tag)).then_some((def, v)) })?; (var_idx, layout) @@ -378,7 +378,7 @@ pub(crate) fn detect_variant_from_bytes<'a>( .filter(|x| x != untagged_variant) .nth(candidate_tag) .unwrap_or(*untagged_variant); - (db.enum_variants(e).variants[variant.0].0, &variants[variant]) + (e.enum_variants(db).variants[variant.0].0, &variants[variant]) } } } diff --git a/crates/hir-ty/src/variance.rs b/crates/hir-ty/src/variance.rs index 62478d4fd8..08a215fecf 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, _, _)| { + e.enum_variants(db).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 c746b88c5b..597da0a3cb 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -688,7 +688,7 @@ impl Module { Adt::Enum(e) => { 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 (variants, diagnostics) = e.id.enum_variants_with_diagnostics(db); let file = e.id.lookup(db).id.file_id; let ast_id_map = db.ast_id_map(file); if let Some(diagnostics) = &diagnostics { @@ -1504,11 +1504,11 @@ impl Enum { } pub fn variants(self, db: &dyn HirDatabase) -> Vec { - db.enum_variants(self.id).variants.iter().map(|&(id, _, _)| Variant { id }).collect() + self.id.enum_variants(db).variants.iter().map(|&(id, _, _)| Variant { id }).collect() } pub fn num_variants(self, db: &dyn HirDatabase) -> usize { - db.enum_variants(self.id).variants.len() + self.id.enum_variants(db).variants.len() } pub fn repr(self, db: &dyn HirDatabase) -> Option { @@ -1606,7 +1606,7 @@ impl Variant { pub fn name(self, db: &dyn HirDatabase) -> Name { let lookup = self.id.lookup(db); let enum_ = lookup.parent; - db.enum_variants(enum_).variants[lookup.index as usize].1.clone() + enum_.enum_variants(db).variants[lookup.index as usize].1.clone() } pub fn fields(self, db: &dyn HirDatabase) -> Vec { diff --git a/crates/hir/src/semantics/child_by_source.rs b/crates/hir/src/semantics/child_by_source.rs index ea44451a8e..0d0bbe367e 100644 --- a/crates/hir/src/semantics/child_by_source.rs +++ b/crates/hir/src/semantics/child_by_source.rs @@ -205,7 +205,7 @@ impl ChildBySource for EnumId { let ast_id_map = db.ast_id_map(loc.id.file_id); - db.enum_variants(*self).variants.iter().for_each(|&(variant, _, _)| { + self.enum_variants(db).variants.iter().for_each(|&(variant, _, _)| { res[keys::ENUM_VARIANT].insert(ast_id_map.get(variant.lookup(db).id.value), variant); }); let (_, source_map) = db.enum_signature_with_source_map(*self); diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index 09b61524d6..3273358b78 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -829,7 +829,7 @@ impl<'db> SourceAnalyzer<'db> { handle_variants(id.into(), subst, &mut container)? } AdtId::EnumId(id) => { - let variants = db.enum_variants(id); + let variants = id.enum_variants(db); let variant = variants.variant(&field_name.as_name())?; container = Either::Left((variant, subst.clone())); (Either::Left(Variant { id: variant }), id.into(), subst.clone()) From 155ef3de60f113b1eef0205b8b9de834977a8ea1 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 15 Jun 2025 09:16:45 +0200 Subject: [PATCH 48/56] Replace unnecessary use of `MacroDefId` with `MacroId` --- crates/hir-def/src/nameres.rs | 6 +++--- crates/hir-def/src/nameres/collector.rs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/hir-def/src/nameres.rs b/crates/hir-def/src/nameres.rs index 610bb6b00b..0837308d5b 100644 --- a/crates/hir-def/src/nameres.rs +++ b/crates/hir-def/src/nameres.rs @@ -62,8 +62,8 @@ use std::ops::Deref; use base_db::Crate; use hir_expand::{ - EditionedFileId, ErasedAstId, HirFileId, InFile, MacroCallId, MacroDefId, mod_path::ModPath, - name::Name, proc_macro::ProcMacroKind, + EditionedFileId, ErasedAstId, HirFileId, InFile, MacroCallId, mod_path::ModPath, name::Name, + proc_macro::ProcMacroKind, }; use intern::Symbol; use itertools::Itertools; @@ -189,7 +189,7 @@ pub struct DefMap { #[derive(Clone, Debug, PartialEq, Eq)] struct DefMapCrateData { /// Side table for resolving derive helpers. - exported_derives: FxHashMap>, + exported_derives: FxHashMap>, fn_proc_macro_mapping: FxHashMap, /// Custom attributes registered with `#![register_attr]`. diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index 3a2faae366..508fcc2fa5 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -609,7 +609,7 @@ impl<'db> DefCollector<'db> { self.define_proc_macro(def.name.clone(), proc_macro_id); let crate_data = Arc::get_mut(&mut self.def_map.data).unwrap(); if let ProcMacroKind::Derive { helpers } = def.kind { - crate_data.exported_derives.insert(self.db.macro_def(proc_macro_id.into()), helpers); + crate_data.exported_derives.insert(proc_macro_id.into(), helpers); } crate_data.fn_proc_macro_mapping.insert(fn_id, proc_macro_id); } @@ -1345,7 +1345,7 @@ impl<'db> DefCollector<'db> { // Record its helper attributes. if def_id.krate != self.def_map.krate { let def_map = crate_def_map(self.db, def_id.krate); - if let Some(helpers) = def_map.data.exported_derives.get(&def_id) { + if let Some(helpers) = def_map.data.exported_derives.get(¯o_id) { self.def_map .derive_helpers_in_scope .entry(ast_id.ast_id.map(|it| it.upcast())) @@ -2425,7 +2425,7 @@ impl ModCollector<'_, '_> { Arc::get_mut(&mut self.def_collector.def_map.data) .unwrap() .exported_derives - .insert(self.def_collector.db.macro_def(macro_id.into()), helpers); + .insert(macro_id.into(), helpers); } } } From 4e392f82cb394f926983c201f9e964a16e78de56 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 15 Jun 2025 09:40:02 +0200 Subject: [PATCH 49/56] Idiomatic salsa use for impl items query --- crates/hir-def/src/db.rs | 13 +------------ crates/hir-def/src/lang_item.rs | 2 +- crates/hir-def/src/lib.rs | 17 ++++++++++++++++- crates/hir-def/src/nameres/assoc.rs | 16 ++++++---------- crates/hir-def/src/nameres/tests/incremental.rs | 1 - crates/hir-ty/src/chalk_db.rs | 6 +++--- crates/hir-ty/src/method_resolution.rs | 8 ++++---- crates/hir-ty/src/tests.rs | 2 +- crates/hir/src/lib.rs | 12 ++++++------ crates/hir/src/semantics/child_by_source.rs | 2 +- crates/hir/src/symbols.rs | 2 +- 11 files changed, 40 insertions(+), 41 deletions(-) diff --git a/crates/hir-def/src/db.rs b/crates/hir-def/src/db.rs index 2fc79c3809..05fba1f7a1 100644 --- a/crates/hir-def/src/db.rs +++ b/crates/hir-def/src/db.rs @@ -25,11 +25,7 @@ use crate::{ import_map::ImportMap, item_tree::{ItemTree, file_item_tree_query}, lang_item::{self, LangItem}, - nameres::{ - assoc::{ImplItems, TraitItems}, - crate_def_map, - diagnostics::DefDiagnostics, - }, + nameres::{assoc::TraitItems, crate_def_map, diagnostics::DefDiagnostics}, signatures::{ ConstSignature, EnumSignature, FunctionSignature, ImplSignature, StaticSignature, StructSignature, TraitAliasSignature, TraitSignature, TypeAliasSignature, UnionSignature, @@ -120,13 +116,6 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + SourceDatabase { id: VariantId, ) -> (Arc, Arc); - #[salsa::transparent] - #[salsa::invoke(ImplItems::impl_items_query)] - fn impl_items(&self, e: ImplId) -> Arc; - - #[salsa::invoke(ImplItems::impl_items_with_diagnostics_query)] - fn impl_items_with_diagnostics(&self, e: ImplId) -> (Arc, DefDiagnostics); - #[salsa::transparent] #[salsa::invoke(TraitItems::trait_items_query)] fn trait_items(&self, e: TraitId) -> Arc; diff --git a/crates/hir-def/src/lang_item.rs b/crates/hir-def/src/lang_item.rs index c0e30ac795..faff7d036a 100644 --- a/crates/hir-def/src/lang_item.rs +++ b/crates/hir-def/src/lang_item.rs @@ -96,7 +96,7 @@ pub fn crate_lang_items(db: &dyn DefDatabase, krate: Crate) -> Option { lang_items.collect_lang_item(db, f, LangItemTarget::Function) diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs index be5bb57ade..ed602d5198 100644 --- a/crates/hir-def/src/lib.rs +++ b/crates/hir-def/src/lib.rs @@ -88,7 +88,10 @@ use crate::{ builtin_type::BuiltinType, db::DefDatabase, hir::generics::{LocalLifetimeParamId, LocalTypeOrConstParamId}, - nameres::{LocalDefMap, block_def_map, crate_def_map, crate_local_def_map}, + nameres::{ + LocalDefMap, assoc::ImplItems, block_def_map, crate_def_map, crate_local_def_map, + diagnostics::DefDiagnostics, + }, signatures::{EnumVariants, InactiveEnumVariantCode, VariantFields}, }; @@ -287,6 +290,18 @@ impl_intern!(TypeAliasId, TypeAliasLoc, intern_type_alias, lookup_intern_type_al type ImplLoc = ItemLoc; impl_intern!(ImplId, ImplLoc, intern_impl, lookup_intern_impl); +impl ImplId { + #[inline] + pub fn impl_items(self, db: &dyn DefDatabase) -> &ImplItems { + &self.impl_items_with_diagnostics(db).0 + } + + #[inline] + pub fn impl_items_with_diagnostics(self, db: &dyn DefDatabase) -> &(ImplItems, DefDiagnostics) { + ImplItems::of(db, self) + } +} + type UseLoc = ItemLoc; impl_intern!(UseId, UseLoc, intern_use, lookup_intern_use); diff --git a/crates/hir-def/src/nameres/assoc.rs b/crates/hir-def/src/nameres/assoc.rs index cf123d14f5..7aaa918d1c 100644 --- a/crates/hir-def/src/nameres/assoc.rs +++ b/crates/hir-def/src/nameres/assoc.rs @@ -100,16 +100,10 @@ pub struct ImplItems { pub macro_calls: ThinVec<(AstId, MacroCallId)>, } +#[salsa::tracked] impl ImplItems { - #[inline] - pub(crate) fn impl_items_query(db: &dyn DefDatabase, id: ImplId) -> Arc { - db.impl_items_with_diagnostics(id).0 - } - - pub(crate) fn impl_items_with_diagnostics_query( - db: &dyn DefDatabase, - id: ImplId, - ) -> (Arc, DefDiagnostics) { + #[salsa::tracked(returns(ref))] + pub fn of(db: &dyn DefDatabase, id: ImplId) -> (ImplItems, DefDiagnostics) { let _p = tracing::info_span!("impl_items_with_diagnostics_query").entered(); let ItemLoc { container: module_id, id: ast_id } = id.lookup(db); @@ -118,9 +112,11 @@ impl ImplItems { 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)) + (ImplItems { items, macro_calls }, DefDiagnostics::new(diagnostics)) } +} +impl ImplItems { pub fn macro_calls(&self) -> impl Iterator, MacroCallId)> + '_ { self.macro_calls.iter().copied() } diff --git a/crates/hir-def/src/nameres/tests/incremental.rs b/crates/hir-def/src/nameres/tests/incremental.rs index 77e706caed..ba75dca3d3 100644 --- a/crates/hir-def/src/nameres/tests/incremental.rs +++ b/crates/hir-def/src/nameres/tests/incremental.rs @@ -431,7 +431,6 @@ pub struct S {} "parse_shim", "real_span_map_shim", "macro_def_shim", - "macro_def_shim", "file_item_tree_query", "ast_id_map_shim", "parse_macro_expansion_shim", diff --git a/crates/hir-ty/src/chalk_db.rs b/crates/hir-ty/src/chalk_db.rs index cf43924513..7945442811 100644 --- a/crates/hir-ty/src/chalk_db.rs +++ b/crates/hir-ty/src/chalk_db.rs @@ -63,7 +63,7 @@ impl chalk_solve::RustIrDatabase for ChalkContext<'_> { ) -> Option> { let alias_id = from_assoc_type_id(assoc_type_id); let trait_sig = self.db.type_alias_signature(alias_id); - self.db.impl_items(hir_def::ImplId::from_chalk(self.db, impl_id)).items.iter().find_map( + hir_def::ImplId::from_chalk(self.db, impl_id).impl_items(self.db).items.iter().find_map( |(name, item)| match item { AssocItemId::TypeAliasId(alias) if &trait_sig.name == name => { Some(TypeAliasAsValue(*alias).to_chalk(self.db)) @@ -880,8 +880,8 @@ fn impl_def_datum(db: &dyn HirDatabase, krate: Crate, impl_id: hir_def::ImplId) let impl_datum_bound = rust_ir::ImplDatumBound { trait_ref, where_clauses }; let trait_data = db.trait_items(trait_); - let associated_ty_value_ids = db - .impl_items(impl_id) + let associated_ty_value_ids = impl_id + .impl_items(db) .items .iter() .filter_map(|(_, item)| match item { diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs index 3b295d41e6..70c89275a5 100644 --- a/crates/hir-ty/src/method_resolution.rs +++ b/crates/hir-ty/src/method_resolution.rs @@ -790,7 +790,7 @@ fn find_matching_impl( mut impls: impl Iterator, mut table: InferenceTable<'_>, actual_trait_ref: TraitRef, -) -> Option<(Arc, Substitution)> { +) -> Option<(&ImplItems, Substitution)> { let db = table.db; impls.find_map(|impl_| { table.run_in_snapshot(|table| { @@ -811,7 +811,7 @@ fn find_matching_impl( let goal = crate::Goal::all(Interner, wcs); table.try_obligation(goal.clone())?; table.register_obligation(goal); - Some((db.impl_items(impl_), table.resolve_completely(impl_substs))) + Some((impl_.impl_items(db), table.resolve_completely(impl_substs))) }) }) } @@ -875,7 +875,7 @@ fn is_inherent_impl_coherent( _ => false, }; - let items = db.impl_items(impl_id); + let items = impl_id.impl_items(db); rustc_has_incoherent_inherent_impls && !items.items.is_empty() && items.items.iter().all(|&(_, assoc)| match assoc { @@ -1462,7 +1462,7 @@ fn iterate_inherent_methods( callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>, ) -> ControlFlow<()> { for &impl_id in impls.for_self_ty(self_ty) { - for &(ref item_name, item) in table.db.impl_items(impl_id).items.iter() { + for &(ref item_name, item) in impl_id.impl_items(table.db).items.iter() { let visible = match is_valid_impl_method_candidate( table, self_ty, diff --git a/crates/hir-ty/src/tests.rs b/crates/hir-ty/src/tests.rs index f2812570ed..9ca6ee476c 100644 --- a/crates/hir-ty/src/tests.rs +++ b/crates/hir-ty/src/tests.rs @@ -437,7 +437,7 @@ pub(crate) fn visit_module( ) { visit_scope(db, crate_def_map, &crate_def_map[module_id].scope, cb); for impl_id in crate_def_map[module_id].scope.impls() { - let impl_data = db.impl_items(impl_id); + let impl_data = impl_id.impl_items(db); for &(_, item) in impl_data.items.iter() { match item { AssocItemId::FunctionId(it) => { diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 597da0a3cb..2614a276bc 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -760,7 +760,7 @@ impl Module { let ast_id_map = db.ast_id_map(file_id); - for diag in db.impl_items_with_diagnostics(impl_def.id).1.iter() { + for diag in impl_def.id.impl_items_with_diagnostics(db).1.iter() { emit_def_diagnostic(db, acc, diag, edition); } @@ -824,7 +824,7 @@ impl Module { AssocItemId::ConstId(id) => !db.const_signature(id).has_body(), AssocItemId::TypeAliasId(it) => db.type_alias_signature(it).ty.is_none(), }); - impl_assoc_items_scratch.extend(db.impl_items(impl_def.id).items.iter().cloned()); + impl_assoc_items_scratch.extend(impl_def.id.impl_items(db).items.iter().cloned()); let redundant = impl_assoc_items_scratch .iter() @@ -912,7 +912,7 @@ impl Module { &source_map, ); - for &(_, item) in db.impl_items(impl_def.id).items.iter() { + for &(_, item) in impl_def.id.impl_items(db).items.iter() { AssocItem::from(item).diagnostics(db, acc, style_lints); } } @@ -4413,7 +4413,7 @@ impl Impl { } pub fn items(self, db: &dyn HirDatabase) -> Vec { - db.impl_items(self.id).items.iter().map(|&(_, it)| it.into()).collect() + self.id.impl_items(db).items.iter().map(|&(_, it)| it.into()).collect() } pub fn is_negative(self, db: &dyn HirDatabase) -> bool { @@ -4462,7 +4462,7 @@ impl Impl { } fn all_macro_calls(&self, db: &dyn HirDatabase) -> Box<[(AstId, MacroCallId)]> { - db.impl_items(self.id).macro_calls.to_vec().into_boxed_slice() + self.id.impl_items(db).macro_calls.to_vec().into_boxed_slice() } } @@ -5271,7 +5271,7 @@ impl Type { let impls = db.inherent_impls_in_crate(krate); for impl_def in impls.for_self_ty(&self.ty) { - for &(_, item) in db.impl_items(*impl_def).items.iter() { + for &(_, item) in impl_def.impl_items(db).items.iter() { if callback(item) { return; } diff --git a/crates/hir/src/semantics/child_by_source.rs b/crates/hir/src/semantics/child_by_source.rs index 0d0bbe367e..fedd8239d0 100644 --- a/crates/hir/src/semantics/child_by_source.rs +++ b/crates/hir/src/semantics/child_by_source.rs @@ -61,7 +61,7 @@ impl ChildBySource for TraitId { impl ChildBySource for ImplId { fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) { - let data = db.impl_items(*self); + let data = self.impl_items(db); data.macro_calls().filter(|(ast_id, _)| ast_id.file_id == file_id).for_each( |(ast_id, call_id)| { let ptr = ast_id.to_ptr(db); diff --git a/crates/hir/src/symbols.rs b/crates/hir/src/symbols.rs index a0815c3131..05f4a830da 100644 --- a/crates/hir/src/symbols.rs +++ b/crates/hir/src/symbols.rs @@ -321,7 +321,7 @@ impl<'a> SymbolCollector<'a> { .to_smolstr(), ); self.with_container_name(impl_name, |s| { - for &(ref name, assoc_item_id) in &self.db.impl_items(impl_id).items { + for &(ref name, assoc_item_id) in &impl_id.impl_items(self.db).items { s.push_assoc_item(assoc_item_id, name, None) } }) From bceeb6a3c74bb90593770b4a6b6de39f0b097a49 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 15 Jun 2025 09:43:42 +0200 Subject: [PATCH 50/56] Idiomatic salsa use for extern block abi query --- crates/hir-def/src/db.rs | 5 +---- crates/hir-def/src/lib.rs | 10 +++++++++- crates/hir-def/src/signatures.rs | 2 +- crates/hir-ty/src/mir/eval/shim.rs | 6 ++---- crates/hir-ty/src/tests/incremental.rs | 4 ++-- crates/hir-ty/src/utils.rs | 2 +- 6 files changed, 16 insertions(+), 13 deletions(-) diff --git a/crates/hir-def/src/db.rs b/crates/hir-def/src/db.rs index 05fba1f7a1..f5ade8bc6f 100644 --- a/crates/hir-def/src/db.rs +++ b/crates/hir-def/src/db.rs @@ -5,7 +5,7 @@ use hir_expand::{ EditionedFileId, HirFileId, InFile, Lookup, MacroCallId, MacroDefId, MacroDefKind, db::ExpandDatabase, }; -use intern::{Symbol, sym}; +use intern::sym; use la_arena::ArenaMap; use syntax::{AstPtr, ast}; use triomphe::Arc; @@ -238,9 +238,6 @@ 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)] diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs index ed602d5198..68f0a4b26e 100644 --- a/crates/hir-def/src/lib.rs +++ b/crates/hir-def/src/lib.rs @@ -49,7 +49,7 @@ pub mod find_path; pub mod import_map; pub mod visibility; -use intern::{Interned, sym}; +use intern::{Interned, Symbol, sym}; pub use rustc_abi as layout; use thin_vec::ThinVec; use triomphe::Arc; @@ -311,6 +311,14 @@ impl_intern!(ExternCrateId, ExternCrateLoc, intern_extern_crate, lookup_intern_e type ExternBlockLoc = ItemLoc; impl_intern!(ExternBlockId, ExternBlockLoc, intern_extern_block, lookup_intern_extern_block); +#[salsa::tracked] +impl ExternBlockId { + #[salsa::tracked] + pub fn abi(self, db: &dyn DefDatabase) -> Option { + signatures::extern_block_abi(db, self) + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct EnumVariantLoc { pub id: AstId, diff --git a/crates/hir-def/src/signatures.rs b/crates/hir-def/src/signatures.rs index c808079011..377a545ebf 100644 --- a/crates/hir-def/src/signatures.rs +++ b/crates/hir-def/src/signatures.rs @@ -965,7 +965,7 @@ impl EnumVariants { } } -pub(crate) fn extern_block_abi_query( +pub(crate) fn extern_block_abi( db: &dyn DefDatabase, extern_block: ExternBlockId, ) -> Option { diff --git a/crates/hir-ty/src/mir/eval/shim.rs b/crates/hir-ty/src/mir/eval/shim.rs index 8d428dd6d0..6ebde01334 100644 --- a/crates/hir-ty/src/mir/eval/shim.rs +++ b/crates/hir-ty/src/mir/eval/shim.rs @@ -65,7 +65,7 @@ impl Evaluator<'_> { Some(abi) => *abi == sym::rust_dash_intrinsic, None => match def.lookup(self.db).container { hir_def::ItemContainerId::ExternBlockId(block) => { - self.db.extern_block_abi(block) == Some(sym::rust_dash_intrinsic) + block.abi(self.db) == Some(sym::rust_dash_intrinsic) } _ => false, }, @@ -84,9 +84,7 @@ impl Evaluator<'_> { ); } let is_extern_c = match def.lookup(self.db).container { - hir_def::ItemContainerId::ExternBlockId(block) => { - self.db.extern_block_abi(block) == Some(sym::C) - } + hir_def::ItemContainerId::ExternBlockId(block) => block.abi(self.db) == Some(sym::C), _ => false, }; if is_extern_c { diff --git a/crates/hir-ty/src/tests/incremental.rs b/crates/hir-ty/src/tests/incremental.rs index b45d8babd4..905fd8a3bc 100644 --- a/crates/hir-ty/src/tests/incremental.rs +++ b/crates/hir-ty/src/tests/incremental.rs @@ -571,7 +571,7 @@ fn main() { "body_shim", "body_with_source_map_shim", "attrs_shim", - "impl_items_with_diagnostics_shim", + "of_", "infer_shim", "trait_signature_shim", "trait_signature_with_source_map_shim", @@ -678,7 +678,7 @@ fn main() { "body_with_source_map_shim", "attrs_shim", "body_shim", - "impl_items_with_diagnostics_shim", + "of_", "infer_shim", "attrs_shim", "trait_signature_with_source_map_shim", diff --git a/crates/hir-ty/src/utils.rs b/crates/hir-ty/src/utils.rs index 867c7ea087..4c8e635eff 100644 --- a/crates/hir-ty/src/utils.rs +++ b/crates/hir-ty/src/utils.rs @@ -293,7 +293,7 @@ pub fn is_fn_unsafe_to_call( let loc = func.lookup(db); match loc.container { hir_def::ItemContainerId::ExternBlockId(block) => { - let is_intrinsic_block = db.extern_block_abi(block) == Some(sym::rust_dash_intrinsic); + let is_intrinsic_block = block.abi(db) == 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 From 4b38ea5abdd498e8641039c38f4366200263c368 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 15 Jun 2025 09:59:56 +0200 Subject: [PATCH 51/56] Unify assoc item visibility queries --- crates/hir-def/src/db.rs | 20 ++---- crates/hir-def/src/lib.rs | 2 +- crates/hir-def/src/visibility.rs | 89 +++++++++++--------------- crates/hir-ty/src/method_resolution.rs | 4 +- crates/hir/src/lib.rs | 22 +++---- 5 files changed, 59 insertions(+), 78 deletions(-) diff --git a/crates/hir-def/src/db.rs b/crates/hir-def/src/db.rs index f5ade8bc6f..c618e4bdce 100644 --- a/crates/hir-def/src/db.rs +++ b/crates/hir-def/src/db.rs @@ -11,10 +11,10 @@ use syntax::{AstPtr, ast}; use triomphe::Arc; use crate::{ - AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, EnumVariantId, EnumVariantLoc, - ExternBlockId, ExternBlockLoc, ExternCrateId, ExternCrateLoc, FunctionId, FunctionLoc, - GenericDefId, ImplId, ImplLoc, LocalFieldId, Macro2Id, Macro2Loc, MacroExpander, MacroId, - MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ProcMacroId, ProcMacroLoc, StaticId, + AssocItemId, AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, EnumVariantId, + EnumVariantLoc, ExternBlockId, ExternBlockLoc, ExternCrateId, ExternCrateLoc, FunctionId, + 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}, @@ -298,16 +298,8 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + SourceDatabase { #[salsa::invoke(visibility::field_visibilities_query)] fn field_visibilities(&self, var: VariantId) -> Arc>; - // FIXME: unify function_visibility and const_visibility? - - #[salsa::invoke(visibility::function_visibility_query)] - fn function_visibility(&self, def: FunctionId) -> Visibility; - - #[salsa::invoke(visibility::const_visibility_query)] - fn const_visibility(&self, def: ConstId) -> Visibility; - - #[salsa::invoke(visibility::type_alias_visibility_query)] - fn type_alias_visibility(&self, def: TypeAliasId) -> Visibility; + #[salsa::invoke(visibility::assoc_visibility_query)] + fn assoc_visibility(&self, def: AssocItemId) -> Visibility; // endregion:visibilities diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs index 68f0a4b26e..0cd7e89432 100644 --- a/crates/hir-def/src/lib.rs +++ b/crates/hir-def/src/lib.rs @@ -793,7 +793,7 @@ impl DefWithBodyId { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, salsa_macros::Supertype)] pub enum AssocItemId { FunctionId(FunctionId), ConstId(ConstId), diff --git a/crates/hir-def/src/visibility.rs b/crates/hir-def/src/visibility.rs index 14d67ea804..aea2ac550e 100644 --- a/crates/hir-def/src/visibility.rs +++ b/crates/hir-def/src/visibility.rs @@ -8,12 +8,8 @@ use syntax::ast::{self, HasVisibility}; use triomphe::Arc; use crate::{ - ConstId, FunctionId, HasModule, ItemContainerId, LocalFieldId, LocalModuleId, ModuleId, - TraitId, TypeAliasId, VariantId, - db::DefDatabase, - nameres::DefMap, - resolver::{HasResolver, Resolver}, - src::HasSource, + AssocItemId, HasModule, ItemContainerId, LocalFieldId, LocalModuleId, ModuleId, TraitId, + VariantId, db::DefDatabase, nameres::DefMap, resolver::HasResolver, src::HasSource, }; pub use crate::item_tree::{RawVisibility, VisibilityExplicitness}; @@ -225,63 +221,56 @@ pub(crate) fn field_visibilities_query( pub fn visibility_from_ast( db: &dyn DefDatabase, - resolver: &Resolver<'_>, + has_resolver: impl HasResolver, 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) + if raw_vis == RawVisibility::Public { + return Visibility::Public; + } + + Visibility::resolve(db, &has_resolver.resolver(db), &raw_vis) } -fn trait_item_visibility( - db: &dyn DefDatabase, - resolver: &Resolver<'_>, - container: ItemContainerId, -) -> Option { +/// Resolve visibility of a type alias. +pub(crate) fn assoc_visibility_query(db: &dyn DefDatabase, def: AssocItemId) -> Visibility { + match def { + AssocItemId::FunctionId(function_id) => { + let loc = function_id.lookup(db); + trait_item_visibility(db, loc.container).unwrap_or_else(|| { + let source = loc.source(db); + visibility_from_ast(db, function_id, source.map(|src| src.visibility())) + }) + } + AssocItemId::ConstId(const_id) => { + let loc = const_id.lookup(db); + trait_item_visibility(db, loc.container).unwrap_or_else(|| { + let source = loc.source(db); + visibility_from_ast(db, const_id, source.map(|src| src.visibility())) + }) + } + AssocItemId::TypeAliasId(type_alias_id) => { + let loc = type_alias_id.lookup(db); + trait_item_visibility(db, loc.container).unwrap_or_else(|| { + let source = loc.source(db); + visibility_from_ast(db, type_alias_id, source.map(|src| src.visibility())) + }) + } + } +} + +fn trait_item_visibility(db: &dyn DefDatabase, container: ItemContainerId) -> Option { match container { - ItemContainerId::TraitId(trait_) => Some(trait_visibility(db, resolver, trait_)), + ItemContainerId::TraitId(trait_) => Some(trait_visibility(db, trait_)), _ => None, } } -/// Resolve visibility of a function. -pub(crate) fn function_visibility_query(db: &dyn DefDatabase, def: FunctionId) -> Visibility { - let loc = def.lookup(db); - let resolver = def.resolver(db); - trait_item_visibility(db, &resolver, loc.container).unwrap_or_else(|| { - let source = loc.source(db); - visibility_from_ast(db, &resolver, source.map(|src| src.visibility())) - }) -} - -/// Resolve visibility of a const. -pub(crate) fn const_visibility_query(db: &dyn DefDatabase, def: ConstId) -> Visibility { - let loc = def.lookup(db); - let resolver = def.resolver(db); - trait_item_visibility(db, &resolver, loc.container).unwrap_or_else(|| { - let source = loc.source(db); - visibility_from_ast(db, &resolver, source.map(|src| src.visibility())) - }) -} - -/// Resolve visibility of a type alias. -pub(crate) fn type_alias_visibility_query(db: &dyn DefDatabase, def: TypeAliasId) -> Visibility { - let loc = def.lookup(db); - let resolver = def.resolver(db); - trait_item_visibility(db, &resolver, loc.container).unwrap_or_else(|| { - let source = loc.source(db); - visibility_from_ast(db, &resolver, source.map(|src| src.visibility())) - }) -} - -pub(crate) fn trait_visibility( - db: &dyn DefDatabase, - resolver: &Resolver<'_>, - def: TraitId, -) -> Visibility { +fn trait_visibility(db: &dyn DefDatabase, def: TraitId) -> Visibility { let loc = def.lookup(db); let source = loc.source(db); - visibility_from_ast(db, resolver, source.map(|src| src.visibility())) + visibility_from_ast(db, def, source.map(|src| src.visibility())) } diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs index 70c89275a5..25f1782bdd 100644 --- a/crates/hir-ty/src/method_resolution.rs +++ b/crates/hir-ty/src/method_resolution.rs @@ -1550,7 +1550,7 @@ fn is_valid_impl_method_candidate( check_that!(name.is_none_or(|n| n == item_name)); if let Some(from_module) = visible_from_module { - if !db.const_visibility(c).is_visible_from(db, from_module) { + if !db.assoc_visibility(c.into()).is_visible_from(db, from_module) { cov_mark::hit!(const_candidate_not_visible); return IsValidCandidate::NotVisible; } @@ -1639,7 +1639,7 @@ fn is_valid_impl_fn_candidate( let data = db.function_signature(fn_id); if let Some(from_module) = visible_from_module { - if !db.function_visibility(fn_id).is_visible_from(db, from_module) { + if !db.assoc_visibility(fn_id.into()).is_visible_from(db, from_module) { cov_mark::hit!(autoderef_candidate_not_visible); return IsValidCandidate::NotVisible; } diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 2614a276bc..adae335627 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -1431,7 +1431,7 @@ impl HasVisibility for Struct { fn visibility(&self, db: &dyn HirDatabase) -> Visibility { let loc = self.id.lookup(db); let source = loc.source(db); - visibility_from_ast(db, &self.id.resolver(db), source.map(|src| src.visibility())) + visibility_from_ast(db, self.id, source.map(|src| src.visibility())) } } @@ -1485,7 +1485,7 @@ impl HasVisibility for Union { fn visibility(&self, db: &dyn HirDatabase) -> Visibility { let loc = self.id.lookup(db); let source = loc.source(db); - visibility_from_ast(db, &self.id.resolver(db), source.map(|src| src.visibility())) + visibility_from_ast(db, self.id, source.map(|src| src.visibility())) } } @@ -1574,7 +1574,7 @@ impl HasVisibility for Enum { fn visibility(&self, db: &dyn HirDatabase) -> Visibility { let loc = self.id.lookup(db); let source = loc.source(db); - visibility_from_ast(db, &self.id.resolver(db), source.map(|src| src.visibility())) + visibility_from_ast(db, self.id, source.map(|src| src.visibility())) } } @@ -2632,7 +2632,7 @@ impl SelfParam { impl HasVisibility for Function { fn visibility(&self, db: &dyn HirDatabase) -> Visibility { - db.function_visibility(self.id) + db.assoc_visibility(self.id.into()) } } @@ -2692,7 +2692,7 @@ impl HasVisibility for ExternCrateDecl { fn visibility(&self, db: &dyn HirDatabase) -> Visibility { let loc = self.id.lookup(db); let source = loc.source(db); - visibility_from_ast(db, &self.id.resolver(db), source.map(|src| src.visibility())) + visibility_from_ast(db, self.id, source.map(|src| src.visibility())) } } @@ -2727,7 +2727,7 @@ impl Const { impl HasVisibility for Const { fn visibility(&self, db: &dyn HirDatabase) -> Visibility { - db.const_visibility(self.id) + db.assoc_visibility(self.id.into()) } } @@ -2813,7 +2813,7 @@ impl HasVisibility for Static { fn visibility(&self, db: &dyn HirDatabase) -> Visibility { let loc = self.id.lookup(db); let source = loc.source(db); - visibility_from_ast(db, &self.id.resolver(db), source.map(|src| src.visibility())) + visibility_from_ast(db, self.id, source.map(|src| src.visibility())) } } @@ -2915,7 +2915,7 @@ impl HasVisibility for Trait { fn visibility(&self, db: &dyn HirDatabase) -> Visibility { let loc = self.id.lookup(db); let source = loc.source(db); - visibility_from_ast(db, &self.id.resolver(db), source.map(|src| src.visibility())) + visibility_from_ast(db, self.id, source.map(|src| src.visibility())) } } @@ -2938,7 +2938,7 @@ impl HasVisibility for TraitAlias { fn visibility(&self, db: &dyn HirDatabase) -> Visibility { let loc = self.id.lookup(db); let source = loc.source(db); - visibility_from_ast(db, &self.id.resolver(db), source.map(|src| src.visibility())) + visibility_from_ast(db, self.id, source.map(|src| src.visibility())) } } @@ -2976,7 +2976,7 @@ impl TypeAlias { impl HasVisibility for TypeAlias { fn visibility(&self, db: &dyn HirDatabase) -> Visibility { - db.type_alias_visibility(self.id) + db.assoc_visibility(self.id.into()) } } @@ -3200,7 +3200,7 @@ impl HasVisibility for Macro { MacroId::Macro2Id(id) => { let loc = id.lookup(db); let source = loc.source(db); - visibility_from_ast(db, &id.resolver(db), source.map(|src| src.visibility())) + visibility_from_ast(db, id, source.map(|src| src.visibility())) } MacroId::MacroRulesId(_) => Visibility::Public, MacroId::ProcMacroId(_) => Visibility::Public, From e129cdc202345024be35c8f10f1ed00cc4e9538e Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 14 Jun 2025 14:33:52 +0200 Subject: [PATCH 52/56] Optimize `pub(crate)` visibility resolution --- crates/hir-def/src/expr_store/pretty.rs | 1 + .../src/expr_store/tests/body/block.rs | 1 - crates/hir-def/src/find_path.rs | 1 + crates/hir-def/src/item_scope.rs | 22 ++------- crates/hir-def/src/item_tree.rs | 11 ++--- crates/hir-def/src/item_tree/pretty.rs | 1 + crates/hir-def/src/nameres/collector.rs | 3 +- crates/hir-def/src/nameres/path_resolution.rs | 1 + crates/hir-def/src/resolver.rs | 1 + crates/hir-def/src/visibility.rs | 47 +++++++++++++++---- crates/hir-ty/src/display.rs | 1 + crates/hir/src/symbols.rs | 1 + 12 files changed, 55 insertions(+), 36 deletions(-) diff --git a/crates/hir-def/src/expr_store/pretty.rs b/crates/hir-def/src/expr_store/pretty.rs index 7b452721df..ae8a959164 100644 --- a/crates/hir-def/src/expr_store/pretty.rs +++ b/crates/hir-def/src/expr_store/pretty.rs @@ -144,6 +144,7 @@ pub fn print_variant_body_hir(db: &dyn DefDatabase, owner: VariantId, edition: E w!(p, "{}", interned.display(db, p.edition)) } crate::item_tree::RawVisibility::Public => w!(p, "pub "), + crate::item_tree::RawVisibility::PubCrate => w!(p, "pub(crate) "), } if *is_unsafe { w!(p, "unsafe "); diff --git a/crates/hir-def/src/expr_store/tests/body/block.rs b/crates/hir-def/src/expr_store/tests/body/block.rs index 5fe7277817..5a694c2092 100644 --- a/crates/hir-def/src/expr_store/tests/body/block.rs +++ b/crates/hir-def/src/expr_store/tests/body/block.rs @@ -457,7 +457,6 @@ fn foo() { #[test] fn is_visible_from_same_def_map() { // Regression test for https://github.com/rust-lang/rust-analyzer/issues/9481 - cov_mark::check!(is_visible_from_same_block_def_map); check_at( r#" fn outer() { diff --git a/crates/hir-def/src/find_path.rs b/crates/hir-def/src/find_path.rs index 6ebc0d8dfd..2820729d60 100644 --- a/crates/hir-def/src/find_path.rs +++ b/crates/hir-def/src/find_path.rs @@ -615,6 +615,7 @@ fn find_local_import_locations( cov_mark::hit!(discount_private_imports); false } + Visibility::PubCrate(_) => true, Visibility::Public => true, }; diff --git a/crates/hir-def/src/item_scope.rs b/crates/hir-def/src/item_scope.rs index 8591874eb9..efa4399468 100644 --- a/crates/hir-def/src/item_scope.rs +++ b/crates/hir-def/src/item_scope.rs @@ -20,7 +20,7 @@ use crate::{ LocalModuleId, Lookup, MacroId, ModuleDefId, ModuleId, TraitId, UseId, db::DefDatabase, per_ns::{Item, MacrosItem, PerNs, TypesItem, ValuesItem}, - visibility::{Visibility, VisibilityExplicitness}, + visibility::Visibility, }; #[derive(Debug, Default)] @@ -720,33 +720,19 @@ impl ItemScope { } /// Marks everything that is not a procedural macro as private to `this_module`. - pub(crate) fn censor_non_proc_macros(&mut self, this_module: ModuleId) { + pub(crate) fn censor_non_proc_macros(&mut self, krate: Crate) { self.types .values_mut() .map(|def| &mut def.vis) .chain(self.values.values_mut().map(|def| &mut def.vis)) .chain(self.unnamed_trait_imports.iter_mut().map(|(_, def)| &mut def.vis)) - .for_each(|vis| match vis { - &mut Visibility::Module(_, visibility_explicitness) => { - *vis = Visibility::Module(this_module, visibility_explicitness) - } - Visibility::Public => { - *vis = Visibility::Module(this_module, VisibilityExplicitness::Implicit) - } - }); + .for_each(|vis| *vis = Visibility::PubCrate(krate)); for mac in self.macros.values_mut() { if matches!(mac.def, MacroId::ProcMacroId(_) if mac.import.is_none()) { continue; } - match mac.vis { - Visibility::Module(_, visibility_explicitness) => { - mac.vis = Visibility::Module(this_module, visibility_explicitness) - } - Visibility::Public => { - mac.vis = Visibility::Module(this_module, VisibilityExplicitness::Implicit) - } - } + mac.vis = Visibility::PubCrate(krate) } } diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs index f61b403b84..bf14c0ecee 100644 --- a/crates/hir-def/src/item_tree.rs +++ b/crates/hir-def/src/item_tree.rs @@ -416,7 +416,7 @@ impl Index for ItemTree { static VIS_PUB: RawVisibility = RawVisibility::Public; static VIS_PRIV_IMPLICIT: OnceLock = OnceLock::new(); static VIS_PRIV_EXPLICIT: OnceLock = OnceLock::new(); - static VIS_PUB_CRATE: OnceLock = OnceLock::new(); + static VIS_PUB_CRATE: RawVisibility = RawVisibility::PubCrate; match index { RawVisibilityId::PRIV_IMPLICIT => VIS_PRIV_IMPLICIT.get_or_init(|| { @@ -432,12 +432,7 @@ impl Index for ItemTree { ) }), RawVisibilityId::PUB => &VIS_PUB, - RawVisibilityId::PUB_CRATE => VIS_PUB_CRATE.get_or_init(|| { - RawVisibility::Module( - Interned::new(ModPath::from_kind(PathKind::Crate)), - VisibilityExplicitness::Explicit, - ) - }), + RawVisibilityId::PUB_CRATE => &VIS_PUB_CRATE, _ => &self.vis.arena[index.0 as usize], } } @@ -555,6 +550,8 @@ pub enum RawVisibility { /// `pub(in module)`, `pub(crate)` or `pub(super)`. Also private, which is /// equivalent to `pub(self)`. Module(Interned, VisibilityExplicitness), + /// `pub(crate)`. + PubCrate, /// `pub`. Public, } diff --git a/crates/hir-def/src/item_tree/pretty.rs b/crates/hir-def/src/item_tree/pretty.rs index eb97081128..a8e816bd3a 100644 --- a/crates/hir-def/src/item_tree/pretty.rs +++ b/crates/hir-def/src/item_tree/pretty.rs @@ -111,6 +111,7 @@ impl Printer<'_> { w!(self, "pub({}) ", path.display(self.db, self.edition)) } RawVisibility::Public => w!(self, "pub "), + RawVisibility::PubCrate => w!(self, "pub(crate) "), }; } diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index 508fcc2fa5..78fdc27560 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -437,9 +437,8 @@ impl<'db> DefCollector<'db> { // Additionally, while the proc macro entry points must be `pub`, they are not publicly // exported in type/value namespace. This function reduces the visibility of all items // in the crate root that aren't proc macros. - let module_id = self.def_map.module_id(DefMap::ROOT); let root = &mut self.def_map.modules[DefMap::ROOT]; - root.scope.censor_non_proc_macros(module_id); + root.scope.censor_non_proc_macros(self.def_map.krate); } } diff --git a/crates/hir-def/src/nameres/path_resolution.rs b/crates/hir-def/src/nameres/path_resolution.rs index ca39173d47..307acaf1fe 100644 --- a/crates/hir-def/src/nameres/path_resolution.rs +++ b/crates/hir-def/src/nameres/path_resolution.rs @@ -129,6 +129,7 @@ impl DefMap { } } RawVisibility::Public => Visibility::Public, + RawVisibility::PubCrate => Visibility::PubCrate(self.krate), }; // In block expressions, `self` normally refers to the containing non-block module, and diff --git a/crates/hir-def/src/resolver.rs b/crates/hir-def/src/resolver.rs index 491b6204bc..7b24f6cc74 100644 --- a/crates/hir-def/src/resolver.rs +++ b/crates/hir-def/src/resolver.rs @@ -305,6 +305,7 @@ impl<'db> Resolver<'db> { }), ) } + RawVisibility::PubCrate => Some(Visibility::PubCrate(self.krate())), RawVisibility::Public => Some(Visibility::Public), } } diff --git a/crates/hir-def/src/visibility.rs b/crates/hir-def/src/visibility.rs index aea2ac550e..11efeed17b 100644 --- a/crates/hir-def/src/visibility.rs +++ b/crates/hir-def/src/visibility.rs @@ -2,6 +2,7 @@ use std::iter; +use base_db::Crate; use hir_expand::{InFile, Lookup}; use la_arena::ArenaMap; use syntax::ast::{self, HasVisibility}; @@ -19,6 +20,8 @@ pub use crate::item_tree::{RawVisibility, VisibilityExplicitness}; pub enum Visibility { /// Visibility is restricted to a certain module. Module(ModuleId, VisibilityExplicitness), + /// Visibility is restricted to the crate. + PubCrate(Crate), /// Visibility is unrestricted. Public, } @@ -41,6 +44,7 @@ impl Visibility { pub fn is_visible_from(self, db: &dyn DefDatabase, from_module: ModuleId) -> bool { let to_module = match self { Visibility::Module(m, _) => m, + Visibility::PubCrate(krate) => return from_module.krate == krate, Visibility::Public => return true, }; // if they're not in the same crate, it can't be visible @@ -59,6 +63,7 @@ impl Visibility { ) -> bool { let to_module = match self { Visibility::Module(m, _) => m, + Visibility::PubCrate(krate) => return def_map.krate() == krate, Visibility::Public => return true, }; // if they're not in the same crate, it can't be visible @@ -132,26 +137,41 @@ impl Visibility { pub(crate) fn max(self, other: Visibility, def_map: &DefMap) -> Option { match (self, other) { (_, Visibility::Public) | (Visibility::Public, _) => Some(Visibility::Public), + (Visibility::PubCrate(krate), Visibility::PubCrate(krateb)) => { + if krate == krateb { + Some(Visibility::PubCrate(krate)) + } else { + None + } + } + (Visibility::Module(mod_, _), Visibility::PubCrate(krate)) + | (Visibility::PubCrate(krate), Visibility::Module(mod_, _)) => { + if mod_.krate == krate { + Some(Visibility::PubCrate(krate)) + } else { + None + } + } (Visibility::Module(mod_a, expl_a), Visibility::Module(mod_b, expl_b)) => { - if mod_a.krate != mod_b.krate { + if mod_a.krate != def_map.krate() || mod_b.krate != def_map.krate() { return None; } let def_block = def_map.block_id(); - if (mod_a.containing_block(), mod_b.containing_block()) != (def_block, def_block) { + if mod_a.containing_block() != def_block || mod_b.containing_block() != def_block { return None; } let mut a_ancestors = iter::successors(Some(mod_a.local_id), |&m| def_map[m].parent); - let mut b_ancestors = - iter::successors(Some(mod_b.local_id), |&m| def_map[m].parent); if a_ancestors.any(|m| m == mod_b.local_id) { // B is above A return Some(Visibility::Module(mod_b, expl_b)); } + let mut b_ancestors = + iter::successors(Some(mod_b.local_id), |&m| def_map[m].parent); if b_ancestors.any(|m| m == mod_a.local_id) { // A is above B return Some(Visibility::Module(mod_a, expl_a)); @@ -169,26 +189,37 @@ impl Visibility { pub(crate) fn min(self, other: Visibility, def_map: &DefMap) -> Option { match (self, other) { (vis, Visibility::Public) | (Visibility::Public, vis) => Some(vis), + (Visibility::PubCrate(krate), Visibility::PubCrate(krateb)) => { + if krate == krateb { + Some(Visibility::PubCrate(krate)) + } else { + None + } + } + (Visibility::Module(mod_, exp), Visibility::PubCrate(krate)) + | (Visibility::PubCrate(krate), Visibility::Module(mod_, exp)) => { + if mod_.krate == krate { Some(Visibility::Module(mod_, exp)) } else { None } + } (Visibility::Module(mod_a, expl_a), Visibility::Module(mod_b, expl_b)) => { - if mod_a.krate != mod_b.krate { + if mod_a.krate != def_map.krate() || mod_b.krate != def_map.krate() { return None; } let def_block = def_map.block_id(); - if (mod_a.containing_block(), mod_b.containing_block()) != (def_block, def_block) { + if mod_a.containing_block() != def_block || mod_b.containing_block() != def_block { return None; } let mut a_ancestors = iter::successors(Some(mod_a.local_id), |&m| def_map[m].parent); - let mut b_ancestors = - iter::successors(Some(mod_b.local_id), |&m| def_map[m].parent); if a_ancestors.any(|m| m == mod_b.local_id) { // B is above A return Some(Visibility::Module(mod_a, expl_a)); } + let mut b_ancestors = + iter::successors(Some(mod_b.local_id), |&m| def_map[m].parent); if b_ancestors.any(|m| m == mod_a.local_id) { // A is above B return Some(Visibility::Module(mod_b, expl_b)); diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs index da21f08a1e..1aa7e0fcf8 100644 --- a/crates/hir-ty/src/display.rs +++ b/crates/hir-ty/src/display.rs @@ -2082,6 +2082,7 @@ pub fn write_visibility( ) -> Result<(), HirDisplayError> { match vis { Visibility::Public => write!(f, "pub "), + Visibility::PubCrate(_) => write!(f, "pub(crate) "), Visibility::Module(vis_id, _) => { let def_map = module_id.def_map(f.db); let root_module_id = def_map.module_id(DefMap::ROOT); diff --git a/crates/hir/src/symbols.rs b/crates/hir/src/symbols.rs index 05f4a830da..d80b704f53 100644 --- a/crates/hir/src/symbols.rs +++ b/crates/hir/src/symbols.rs @@ -164,6 +164,7 @@ impl<'a> SymbolCollector<'a> { let is_explicit_import = |vis| match vis { Visibility::Public => true, + Visibility::PubCrate(_) => true, Visibility::Module(_, VisibilityExplicitness::Explicit) => true, Visibility::Module(_, VisibilityExplicitness::Implicit) => false, }; From b3768cdc0e69cf8a5810f21f12e9adb8ac0682b9 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 14 Jun 2025 15:33:48 +0200 Subject: [PATCH 53/56] Optimize private visibility resolution --- crates/hir-def/src/expr_store/pretty.rs | 3 +- .../src/expr_store/tests/body/block.rs | 1 - crates/hir-def/src/find_path.rs | 1 - crates/hir-def/src/item_tree.rs | 22 ++++----- crates/hir-def/src/item_tree/pretty.rs | 3 +- crates/hir-def/src/item_tree/tests.rs | 2 +- crates/hir-def/src/lib.rs | 4 ++ crates/hir-def/src/nameres/path_resolution.rs | 36 ++++++++------ crates/hir-def/src/resolver.rs | 3 ++ crates/hir-def/src/visibility.rs | 47 +++++++++++++++++-- 10 files changed, 83 insertions(+), 39 deletions(-) diff --git a/crates/hir-def/src/expr_store/pretty.rs b/crates/hir-def/src/expr_store/pretty.rs index ae8a959164..56c7655f9e 100644 --- a/crates/hir-def/src/expr_store/pretty.rs +++ b/crates/hir-def/src/expr_store/pretty.rs @@ -141,10 +141,11 @@ pub fn print_variant_body_hir(db: &dyn DefDatabase, owner: VariantId, edition: E let FieldData { name, type_ref, visibility, is_unsafe } = data; match visibility { crate::item_tree::RawVisibility::Module(interned, _visibility_explicitness) => { - w!(p, "{}", interned.display(db, p.edition)) + w!(p, "pub(in {})", interned.display(db, p.edition)) } crate::item_tree::RawVisibility::Public => w!(p, "pub "), crate::item_tree::RawVisibility::PubCrate => w!(p, "pub(crate) "), + crate::item_tree::RawVisibility::PubSelf(_) => w!(p, "pub(self) "), } if *is_unsafe { w!(p, "unsafe "); diff --git a/crates/hir-def/src/expr_store/tests/body/block.rs b/crates/hir-def/src/expr_store/tests/body/block.rs index 5a694c2092..bb0b70bc5b 100644 --- a/crates/hir-def/src/expr_store/tests/body/block.rs +++ b/crates/hir-def/src/expr_store/tests/body/block.rs @@ -397,7 +397,6 @@ fn main() { fn underscore_import() { // This used to panic, because the default (private) visibility inside block expressions would // point into the containing `DefMap`, which visibilities should never be able to do. - cov_mark::check!(adjust_vis_in_block_def_map); check_at( r#" mod m { diff --git a/crates/hir-def/src/find_path.rs b/crates/hir-def/src/find_path.rs index 2820729d60..dccfff002f 100644 --- a/crates/hir-def/src/find_path.rs +++ b/crates/hir-def/src/find_path.rs @@ -1287,7 +1287,6 @@ $0 #[test] fn explicit_private_imports_crate() { - cov_mark::check!(explicit_private_imports); check_found_path( r#" //- /main.rs diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs index bf14c0ecee..c633339857 100644 --- a/crates/hir-def/src/item_tree.rs +++ b/crates/hir-def/src/item_tree.rs @@ -414,23 +414,15 @@ impl Index for ItemTree { type Output = RawVisibility; fn index(&self, index: RawVisibilityId) -> &Self::Output { static VIS_PUB: RawVisibility = RawVisibility::Public; - static VIS_PRIV_IMPLICIT: OnceLock = OnceLock::new(); - static VIS_PRIV_EXPLICIT: OnceLock = OnceLock::new(); + static VIS_PRIV_IMPLICIT: RawVisibility = + RawVisibility::PubSelf(VisibilityExplicitness::Implicit); + static VIS_PRIV_EXPLICIT: RawVisibility = + RawVisibility::PubSelf(VisibilityExplicitness::Explicit); static VIS_PUB_CRATE: RawVisibility = RawVisibility::PubCrate; match index { - RawVisibilityId::PRIV_IMPLICIT => VIS_PRIV_IMPLICIT.get_or_init(|| { - RawVisibility::Module( - Interned::new(ModPath::from_kind(PathKind::SELF)), - VisibilityExplicitness::Implicit, - ) - }), - RawVisibilityId::PRIV_EXPLICIT => VIS_PRIV_EXPLICIT.get_or_init(|| { - RawVisibility::Module( - Interned::new(ModPath::from_kind(PathKind::SELF)), - VisibilityExplicitness::Explicit, - ) - }), + RawVisibilityId::PRIV_IMPLICIT => &VIS_PRIV_IMPLICIT, + RawVisibilityId::PRIV_EXPLICIT => &VIS_PRIV_EXPLICIT, RawVisibilityId::PUB => &VIS_PUB, RawVisibilityId::PUB_CRATE => &VIS_PUB_CRATE, _ => &self.vis.arena[index.0 as usize], @@ -550,6 +542,8 @@ pub enum RawVisibility { /// `pub(in module)`, `pub(crate)` or `pub(super)`. Also private, which is /// equivalent to `pub(self)`. Module(Interned, VisibilityExplicitness), + /// `pub(self)`. + PubSelf(VisibilityExplicitness), /// `pub(crate)`. PubCrate, /// `pub`. diff --git a/crates/hir-def/src/item_tree/pretty.rs b/crates/hir-def/src/item_tree/pretty.rs index a8e816bd3a..696174cb07 100644 --- a/crates/hir-def/src/item_tree/pretty.rs +++ b/crates/hir-def/src/item_tree/pretty.rs @@ -108,10 +108,11 @@ impl Printer<'_> { fn print_visibility(&mut self, vis: RawVisibilityId) { match &self.tree[vis] { RawVisibility::Module(path, _expl) => { - w!(self, "pub({}) ", path.display(self.db, self.edition)) + w!(self, "pub(in {}) ", path.display(self.db, self.edition)) } RawVisibility::Public => w!(self, "pub "), RawVisibility::PubCrate => w!(self, "pub(crate) "), + RawVisibility::PubSelf(_) => w!(self, "pub(self) "), }; } diff --git a/crates/hir-def/src/item_tree/tests.rs b/crates/hir-def/src/item_tree/tests.rs index e39efd31c6..5923b3ea49 100644 --- a/crates/hir-def/src/item_tree/tests.rs +++ b/crates/hir-def/src/item_tree/tests.rs @@ -39,7 +39,7 @@ use a::{c, d::{e}}; pub(self) extern crate self as renamed; // AstId: ExternCrate[7E1C, 0] - pub(super) extern crate bli; + pub(in super) extern crate bli; // AstId: Use[0000, 0] pub use crate::path::{nested, items as renamed, Trait as _}; diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs index 0cd7e89432..a542214d30 100644 --- a/crates/hir-def/src/lib.rs +++ b/crates/hir-def/src/lib.rs @@ -149,6 +149,7 @@ impl HasModule for ItemLoc { #[derive(Debug)] pub struct AssocItemLoc { + // FIXME: Store this as an erased `salsa::Id` to save space pub container: ItemContainerId, pub id: AstId, } @@ -577,6 +578,7 @@ pub type LocalModuleId = Idx; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct FieldId { + // FIXME: Store this as an erased `salsa::Id` to save space pub parent: VariantId, pub local_id: LocalFieldId, } @@ -592,6 +594,7 @@ pub struct TupleFieldId { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct TypeOrConstParamId { + // FIXME: Store this as an erased `salsa::Id` to save space pub parent: GenericDefId, pub local_id: LocalTypeOrConstParamId, } @@ -650,6 +653,7 @@ impl From for TypeOrConstParamId { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct LifetimeParamId { + // FIXME: Store this as an erased `salsa::Id` to save space pub parent: GenericDefId, pub local_id: LocalLifetimeParamId, } diff --git a/crates/hir-def/src/nameres/path_resolution.rs b/crates/hir-def/src/nameres/path_resolution.rs index 307acaf1fe..e8235b1c96 100644 --- a/crates/hir-def/src/nameres/path_resolution.rs +++ b/crates/hir-def/src/nameres/path_resolution.rs @@ -106,7 +106,7 @@ impl DefMap { visibility: &RawVisibility, within_impl: bool, ) -> Option { - let mut vis = match visibility { + let vis = match visibility { RawVisibility::Module(path, explicitness) => { let (result, remaining) = self.resolve_path( local_def_map, @@ -120,30 +120,36 @@ impl DefMap { return None; } let types = result.take_types()?; - match types { + let mut vis = match types { ModuleDefId::ModuleId(m) => Visibility::Module(m, *explicitness), // error: visibility needs to refer to module _ => { return None; } + }; + + // In block expressions, `self` normally refers to the containing non-block module, and + // `super` to its parent (etc.). However, visibilities must only refer to a module in the + // DefMap they're written in, so we restrict them when that happens. + if let Visibility::Module(m, mv) = vis { + // ...unless we're resolving visibility for an associated item in an impl. + if self.block_id() != m.block && !within_impl { + vis = Visibility::Module(self.module_id(Self::ROOT), mv); + tracing::debug!( + "visibility {:?} points outside DefMap, adjusting to {:?}", + m, + vis + ); + } } + vis + } + RawVisibility::PubSelf(explicitness) => { + Visibility::Module(self.module_id(original_module), *explicitness) } RawVisibility::Public => Visibility::Public, RawVisibility::PubCrate => Visibility::PubCrate(self.krate), }; - - // In block expressions, `self` normally refers to the containing non-block module, and - // `super` to its parent (etc.). However, visibilities must only refer to a module in the - // DefMap they're written in, so we restrict them when that happens. - if let Visibility::Module(m, mv) = vis { - // ...unless we're resolving visibility for an associated item in an impl. - if self.block_id() != m.block && !within_impl { - cov_mark::hit!(adjust_vis_in_block_def_map); - vis = Visibility::Module(self.module_id(Self::ROOT), mv); - tracing::debug!("visibility {:?} points outside DefMap, adjusting to {:?}", m, vis); - } - } - Some(vis) } diff --git a/crates/hir-def/src/resolver.rs b/crates/hir-def/src/resolver.rs index 7b24f6cc74..6f321980af 100644 --- a/crates/hir-def/src/resolver.rs +++ b/crates/hir-def/src/resolver.rs @@ -305,6 +305,9 @@ impl<'db> Resolver<'db> { }), ) } + RawVisibility::PubSelf(explicitness) => { + Some(Visibility::Module(self.module(), *explicitness)) + } RawVisibility::PubCrate => Some(Visibility::PubCrate(self.krate())), RawVisibility::Public => Some(Visibility::Public), } diff --git a/crates/hir-def/src/visibility.rs b/crates/hir-def/src/visibility.rs index 11efeed17b..2514e88864 100644 --- a/crates/hir-def/src/visibility.rs +++ b/crates/hir-def/src/visibility.rs @@ -47,6 +47,10 @@ impl Visibility { Visibility::PubCrate(krate) => return from_module.krate == krate, Visibility::Public => return true, }; + if from_module == to_module { + // if the modules are the same, visibility is trivially satisfied + return true; + } // if they're not in the same crate, it can't be visible if from_module.krate != to_module.krate { return false; @@ -70,6 +74,11 @@ impl Visibility { if def_map.krate() != to_module.krate { return false; } + + if from_module == to_module.local_id && def_map.block_id() == to_module.block { + // if the modules are the same, visibility is trivially satisfied + return true; + } Self::is_visible_from_def_map_(db, def_map, to_module, from_module) } @@ -93,9 +102,7 @@ impl Visibility { // `to_module` is not a block, so there is no parent def map to use. (None, _) => (), // `to_module` is at `def_map`'s block, no need to move further. - (Some(a), Some(b)) if a == b => { - cov_mark::hit!(is_visible_from_same_block_def_map); - } + (Some(a), Some(b)) if a == b => {} _ => { if let Some(parent) = to_module.def_map(db).parent() { to_module = parent; @@ -153,7 +160,22 @@ impl Visibility { } } (Visibility::Module(mod_a, expl_a), Visibility::Module(mod_b, expl_b)) => { - if mod_a.krate != def_map.krate() || mod_b.krate != def_map.krate() { + if mod_a == mod_b { + // Most module visibilities are `pub(self)`, and assuming no errors + // this will be the common and thus fast path. + return Some(Visibility::Module( + mod_a, + match (expl_a, expl_b) { + (VisibilityExplicitness::Explicit, _) + | (_, VisibilityExplicitness::Explicit) => { + VisibilityExplicitness::Explicit + } + _ => VisibilityExplicitness::Implicit, + }, + )); + } + + if mod_a.krate() != def_map.krate() || mod_b.krate() != def_map.krate() { return None; } @@ -201,7 +223,22 @@ impl Visibility { if mod_.krate == krate { Some(Visibility::Module(mod_, exp)) } else { None } } (Visibility::Module(mod_a, expl_a), Visibility::Module(mod_b, expl_b)) => { - if mod_a.krate != def_map.krate() || mod_b.krate != def_map.krate() { + if mod_a == mod_b { + // Most module visibilities are `pub(self)`, and assuming no errors + // this will be the common and thus fast path. + return Some(Visibility::Module( + mod_a, + match (expl_a, expl_b) { + (VisibilityExplicitness::Explicit, _) + | (_, VisibilityExplicitness::Explicit) => { + VisibilityExplicitness::Explicit + } + _ => VisibilityExplicitness::Implicit, + }, + )); + } + + if mod_a.krate() != def_map.krate() || mod_b.krate() != def_map.krate() { return None; } From 12226b704a9a382ad59cec7188d1667f3acba04e Mon Sep 17 00:00:00 2001 From: Tadeo Kondrak Date: Sun, 15 Jun 2025 17:42:06 +0200 Subject: [PATCH 54/56] Fix spacing for LIFETIME_IDENT near keywords and literals in test output --- crates/hir-def/src/macro_expansion_tests/mbe.rs | 2 +- .../src/macro_expansion_tests/mbe/regression.rs | 2 +- crates/hir-def/src/macro_expansion_tests/mod.rs | 12 ++++++++++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/crates/hir-def/src/macro_expansion_tests/mbe.rs b/crates/hir-def/src/macro_expansion_tests/mbe.rs index ef93a2a790..c6d901ec93 100644 --- a/crates/hir-def/src/macro_expansion_tests/mbe.rs +++ b/crates/hir-def/src/macro_expansion_tests/mbe.rs @@ -2046,7 +2046,7 @@ macro_rules! m { ($($x:expr)'a*) => (stringify!($($x)'b*)); } fn f() { - let _ = stringify!(0 'b1 'b2); + let _ = stringify!(0 'b 1 'b 2); } "#]], ); diff --git a/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs b/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs index 2cc3ca8c75..e2022c7967 100644 --- a/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs +++ b/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs @@ -784,7 +784,7 @@ macro_rules! delegate_impl { } } } -impl <> Data for &'amut G where G: Data {} +impl <> Data for &'a mut G where G: Data {} "#]], ); } diff --git a/crates/hir-def/src/macro_expansion_tests/mod.rs b/crates/hir-def/src/macro_expansion_tests/mod.rs index b532156091..15b31c1e7e 100644 --- a/crates/hir-def/src/macro_expansion_tests/mod.rs +++ b/crates/hir-def/src/macro_expansion_tests/mod.rs @@ -308,8 +308,16 @@ fn pretty_print_macro_expansion( { " " } - (IDENT, _) if curr_kind.is_keyword(Edition::CURRENT) => " ", - (_, IDENT) if prev_kind.is_keyword(Edition::CURRENT) => " ", + (IDENT | LIFETIME_IDENT, _) + if curr_kind.is_keyword(Edition::CURRENT) || curr_kind.is_literal() => + { + " " + } + (_, IDENT | LIFETIME_IDENT) + if prev_kind.is_keyword(Edition::CURRENT) || prev_kind.is_literal() => + { + " " + } (T![>], IDENT) => " ", (T![>], _) if curr_kind.is_keyword(Edition::CURRENT) => " ", (T![->], _) | (_, T![->]) => " ", From 2070e9a8f393528b716ff6b7df52ecc0564b9d62 Mon Sep 17 00:00:00 2001 From: Tadeo Kondrak Date: Sun, 15 Jun 2025 18:23:18 +0200 Subject: [PATCH 55/56] Use is_any_identifier in pretty_print_macro_expansion --- .../hir-def/src/macro_expansion_tests/mod.rs | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/crates/hir-def/src/macro_expansion_tests/mod.rs b/crates/hir-def/src/macro_expansion_tests/mod.rs index 15b31c1e7e..1c69b37f16 100644 --- a/crates/hir-def/src/macro_expansion_tests/mod.rs +++ b/crates/hir-def/src/macro_expansion_tests/mod.rs @@ -302,19 +302,12 @@ fn pretty_print_macro_expansion( (_, T!['{']) => " ", (T![;] | T!['{'] | T!['}'], _) => "\n", (_, T!['}']) => "\n", - (IDENT | LIFETIME_IDENT, IDENT | LIFETIME_IDENT) => " ", - _ if prev_kind.is_keyword(Edition::CURRENT) - && curr_kind.is_keyword(Edition::CURRENT) => - { - " " - } - (IDENT | LIFETIME_IDENT, _) - if curr_kind.is_keyword(Edition::CURRENT) || curr_kind.is_literal() => - { - " " - } - (_, IDENT | LIFETIME_IDENT) - if prev_kind.is_keyword(Edition::CURRENT) || prev_kind.is_literal() => + _ if (prev_kind.is_any_identifier() + || prev_kind == LIFETIME_IDENT + || prev_kind.is_literal()) + && (curr_kind.is_any_identifier() + || curr_kind == LIFETIME_IDENT + || curr_kind.is_literal()) => { " " } From 10ebd0e3c9520252649a3cb73302f38afdb43cf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Tue, 17 Jun 2025 19:00:01 +0300 Subject: [PATCH 56/56] Try to downgrade object --- Cargo.lock | 13 ++----------- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c2b4e21483..2c7b464164 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -60,7 +60,7 @@ dependencies = [ "cfg-if", "libc", "miniz_oxide", - "object 0.36.7", + "object", "rustc-demangle", "windows-targets 0.52.6", ] @@ -1400,15 +1400,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "object" -version = "0.37.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03fd943161069e1768b4b3d050890ba48730e590f57e56d4aa04e7e090e61b4a" -dependencies = [ - "memchr", -] - [[package]] name = "once_cell" version = "1.21.3" @@ -1573,7 +1564,7 @@ dependencies = [ "libc", "libloading", "memmap2", - "object 0.37.1", + "object", "paths", "proc-macro-test", "ra-ap-rustc_lexer", diff --git a/Cargo.toml b/Cargo.toml index c791d741b0..449c75859c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -122,7 +122,7 @@ libloading = "0.8.8" memmap2 = "0.9.5" nohash-hasher = "0.2.0" oorandom = "11.1.5" -object = { version = "0.37.1", default-features = false, features = [ +object = { version = "0.36.7", default-features = false, features = [ "std", "read_core", "elf",