From d15f2a4fe8dc05ce6d743b53eab5a7c210701226 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Wed, 21 May 2025 00:04:59 +0300 Subject: [PATCH 1/6] 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 | 342 +++---- crates/proc-macro-srv/src/tests/utils.rs | 34 +- crates/span/Cargo.toml | 3 + crates/span/src/ast_id.rs | 903 +++++++++++++++--- crates/span/src/lib.rs | 24 +- crates/span/src/map.rs | 2 +- crates/syntax/src/ast/node_ext.rs | 10 + 22 files changed, 1229 insertions(+), 555 deletions(-) diff --git a/crates/hir-def/src/expr_store/lower.rs b/crates/hir-def/src/expr_store/lower.rs index 29871f5e04db..b7a482a85dbb 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 47c6eb13293f..51172c0a1ee3 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 824fbfa5921a..b9ac3aa73129 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[83AF, 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[CA8D, 0] #[doc = " comment on Unit"] Unit, - // AstId: 7 + // AstId: Variant[F89F, 0] #[doc = " comment on Tuple"] Tuple( pub(self) 0, ), - // AstId: 8 + // AstId: Variant[C117, 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 38fc4b3d118a..eea50d16f5a0 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 b2e1adc3650d..d5ae6f8d885d 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 62b7b638e7b6..d5874f829ba5 100644 --- a/crates/hir-expand/src/builtin/quote.rs +++ b/crates/hir-expand/src/builtin/quote.rs @@ -277,8 +277,8 @@ mod tests { assert_eq!(quoted.to_string(), "hello"); let t = format!("{quoted:#?}"); expect![[r#" - SUBTREE $$ 937550:0@0..0#ROOT2024 937550:0@0..0#ROOT2024 - IDENT hello 937550:0@0..0#ROOT2024"#]] + SUBTREE $$ 937550:Root[0000, 0]@0..0#ROOT2024 937550:Root[0000, 0]@0..0#ROOT2024 + IDENT hello 937550:Root[0000, 0]@0..0#ROOT2024"#]] .assert_eq(&t); } diff --git a/crates/hir-expand/src/files.rs b/crates/hir-expand/src/files.rs index 8024823cbc5c..e8f6b82434ee 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 769455faac04..56034516ef3b 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 55185aa492de..4e1526fe48bd 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 fcea75ef672a..e3b0614546de 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 f54dff1f2d82..25a49fbff9fd 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 c49159df9916..c64a9833e3ff 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 223c5a54b703..22afa018de01 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 18532706c4aa..3b9c45894c60 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 5d1271ba81e1..b071ad80f5b6 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 3a6ce639d135..5e0bc27e2420 100644 --- a/crates/proc-macro-srv/src/tests/mod.rs +++ b/crates/proc-macro-srv/src/tests/mod.rs @@ -21,14 +21,14 @@ fn test_derive_empty() { SUBTREE $$ 1 1"#]], expect![[r#" - SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024 - IDENT struct 42:2@0..6#ROOT2024 - IDENT S 42:2@7..8#ROOT2024 - PUNCH ; [alone] 42:2@8..9#ROOT2024 + SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024 + IDENT struct 42:Root[0000, 0]@0..6#ROOT2024 + IDENT S 42:Root[0000, 0]@7..8#ROOT2024 + PUNCH ; [alone] 42:Root[0000, 0]@8..9#ROOT2024 - SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024"#]], + SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024"#]], ); } @@ -52,19 +52,19 @@ fn test_derive_error() { LITERAL Str #[derive(DeriveError)] struct S ; 1 PUNCH ; [alone] 1"#]], expect![[r#" - SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024 - IDENT struct 42:2@0..6#ROOT2024 - IDENT S 42:2@7..8#ROOT2024 - PUNCH ; [alone] 42:2@8..9#ROOT2024 + SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024 + IDENT struct 42:Root[0000, 0]@0..6#ROOT2024 + IDENT S 42:Root[0000, 0]@7..8#ROOT2024 + PUNCH ; [alone] 42:Root[0000, 0]@8..9#ROOT2024 - SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024 - IDENT compile_error 42:2@0..100#ROOT2024 - PUNCH ! [alone] 42:2@0..100#ROOT2024 - SUBTREE () 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024 - LITERAL Str #[derive(DeriveError)] struct S ; 42:2@0..100#ROOT2024 - PUNCH ; [alone] 42:2@0..100#ROOT2024"#]], + SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024 + IDENT compile_error 42:Root[0000, 0]@0..100#ROOT2024 + PUNCH ! [alone] 42:Root[0000, 0]@0..100#ROOT2024 + SUBTREE () 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024 + LITERAL Str #[derive(DeriveError)] struct S ; 42:Root[0000, 0]@0..100#ROOT2024 + PUNCH ; [alone] 42:Root[0000, 0]@0..100#ROOT2024"#]], ); } @@ -94,25 +94,25 @@ fn test_fn_like_macro_noop() { PUNCH , [alone] 1 SUBTREE [] 1 1"#]], expect![[r#" - SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024 - IDENT ident 42:2@0..5#ROOT2024 - PUNCH , [alone] 42:2@5..6#ROOT2024 - LITERAL Integer 0 42:2@7..8#ROOT2024 - PUNCH , [alone] 42:2@8..9#ROOT2024 - LITERAL Integer 1 42:2@10..11#ROOT2024 - PUNCH , [alone] 42:2@11..12#ROOT2024 - SUBTREE [] 42:2@13..14#ROOT2024 42:2@14..15#ROOT2024 - - - - SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024 - IDENT ident 42:2@0..5#ROOT2024 - PUNCH , [alone] 42:2@5..6#ROOT2024 - LITERAL Integer 0 42:2@7..8#ROOT2024 - PUNCH , [alone] 42:2@8..9#ROOT2024 - LITERAL Integer 1 42:2@10..11#ROOT2024 - PUNCH , [alone] 42:2@11..12#ROOT2024 - SUBTREE [] 42:2@13..14#ROOT2024 42:2@14..15#ROOT2024"#]], + SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024 + IDENT ident 42:Root[0000, 0]@0..5#ROOT2024 + PUNCH , [alone] 42:Root[0000, 0]@5..6#ROOT2024 + LITERAL Integer 0 42:Root[0000, 0]@7..8#ROOT2024 + PUNCH , [alone] 42:Root[0000, 0]@8..9#ROOT2024 + LITERAL Integer 1 42:Root[0000, 0]@10..11#ROOT2024 + PUNCH , [alone] 42:Root[0000, 0]@11..12#ROOT2024 + SUBTREE [] 42:Root[0000, 0]@13..14#ROOT2024 42:Root[0000, 0]@14..15#ROOT2024 + + + + SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024 + IDENT ident 42:Root[0000, 0]@0..5#ROOT2024 + PUNCH , [alone] 42:Root[0000, 0]@5..6#ROOT2024 + LITERAL Integer 0 42:Root[0000, 0]@7..8#ROOT2024 + PUNCH , [alone] 42:Root[0000, 0]@8..9#ROOT2024 + LITERAL Integer 1 42:Root[0000, 0]@10..11#ROOT2024 + PUNCH , [alone] 42:Root[0000, 0]@11..12#ROOT2024 + SUBTREE [] 42:Root[0000, 0]@13..14#ROOT2024 42:Root[0000, 0]@14..15#ROOT2024"#]], ); } @@ -134,17 +134,17 @@ fn test_fn_like_macro_clone_ident_subtree() { PUNCH , [alone] 1 SUBTREE [] 1 1"#]], expect![[r#" - SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024 - IDENT ident 42:2@0..5#ROOT2024 - PUNCH , [alone] 42:2@5..6#ROOT2024 - SUBTREE [] 42:2@7..8#ROOT2024 42:2@8..9#ROOT2024 + SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024 + IDENT ident 42:Root[0000, 0]@0..5#ROOT2024 + PUNCH , [alone] 42:Root[0000, 0]@5..6#ROOT2024 + SUBTREE [] 42:Root[0000, 0]@7..8#ROOT2024 42:Root[0000, 0]@8..9#ROOT2024 - SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024 - IDENT ident 42:2@0..5#ROOT2024 - PUNCH , [alone] 42:2@5..6#ROOT2024 - SUBTREE [] 42:2@7..9#ROOT2024 42:2@7..9#ROOT2024"#]], + SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024 + IDENT ident 42:Root[0000, 0]@0..5#ROOT2024 + PUNCH , [alone] 42:Root[0000, 0]@5..6#ROOT2024 + SUBTREE [] 42:Root[0000, 0]@7..9#ROOT2024 42:Root[0000, 0]@7..9#ROOT2024"#]], ); } @@ -162,13 +162,13 @@ fn test_fn_like_macro_clone_raw_ident() { SUBTREE $$ 1 1 IDENT r#async 1"#]], expect![[r#" - SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024 - IDENT r#async 42:2@0..7#ROOT2024 + SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024 + IDENT r#async 42:Root[0000, 0]@0..7#ROOT2024 - SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024 - IDENT r#async 42:2@0..7#ROOT2024"#]], + SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024 + IDENT r#async 42:Root[0000, 0]@0..7#ROOT2024"#]], ); } @@ -187,14 +187,14 @@ fn test_fn_like_fn_like_span_join() { SUBTREE $$ 1 1 IDENT r#joined 1"#]], expect![[r#" - SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024 - IDENT foo 42:2@0..3#ROOT2024 - IDENT bar 42:2@8..11#ROOT2024 + SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024 + IDENT foo 42:Root[0000, 0]@0..3#ROOT2024 + IDENT bar 42:Root[0000, 0]@8..11#ROOT2024 - SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024 - IDENT r#joined 42:2@0..11#ROOT2024"#]], + SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024 + IDENT r#joined 42:Root[0000, 0]@0..11#ROOT2024"#]], ); } @@ -216,17 +216,17 @@ fn test_fn_like_fn_like_span_ops() { IDENT resolved_at_def_site 1 IDENT start_span 1"#]], expect![[r#" - SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024 - IDENT set_def_site 42:2@0..12#ROOT2024 - IDENT resolved_at_def_site 42:2@13..33#ROOT2024 - IDENT start_span 42:2@34..44#ROOT2024 + SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024 + IDENT set_def_site 42:Root[0000, 0]@0..12#ROOT2024 + IDENT resolved_at_def_site 42:Root[0000, 0]@13..33#ROOT2024 + IDENT start_span 42:Root[0000, 0]@34..44#ROOT2024 - SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024 - IDENT set_def_site 41:1@0..150#ROOT2024 - IDENT resolved_at_def_site 42:2@13..33#ROOT2024 - IDENT start_span 42:2@34..34#ROOT2024"#]], + SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024 + IDENT set_def_site 41:Root[0000, 0]@0..150#ROOT2024 + IDENT resolved_at_def_site 42:Root[0000, 0]@13..33#ROOT2024 + IDENT start_span 42:Root[0000, 0]@34..34#ROOT2024"#]], ); } @@ -258,27 +258,27 @@ fn test_fn_like_mk_literals() { PUNCH - [alone] 1 LITERAL Integer 123 1"#]], expect![[r#" - SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024 - - - - SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024 - LITERAL ByteStr byte_string 42:2@0..100#ROOT2024 - LITERAL Char c 42:2@0..100#ROOT2024 - LITERAL Str string 42:2@0..100#ROOT2024 - LITERAL CStr cstring 42:2@0..100#ROOT2024 - LITERAL Float 3.14f64 42:2@0..100#ROOT2024 - PUNCH - [alone] 42:2@0..100#ROOT2024 - LITERAL Float 3.14f64 42:2@0..100#ROOT2024 - LITERAL Float 3.14 42:2@0..100#ROOT2024 - PUNCH - [alone] 42:2@0..100#ROOT2024 - LITERAL Float 3.14 42:2@0..100#ROOT2024 - LITERAL Integer 123i64 42:2@0..100#ROOT2024 - PUNCH - [alone] 42:2@0..100#ROOT2024 - LITERAL Integer 123i64 42:2@0..100#ROOT2024 - LITERAL Integer 123 42:2@0..100#ROOT2024 - PUNCH - [alone] 42:2@0..100#ROOT2024 - LITERAL Integer 123 42:2@0..100#ROOT2024"#]], + SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024 + + + + SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024 + LITERAL ByteStr byte_string 42:Root[0000, 0]@0..100#ROOT2024 + LITERAL Char c 42:Root[0000, 0]@0..100#ROOT2024 + LITERAL Str string 42:Root[0000, 0]@0..100#ROOT2024 + LITERAL CStr cstring 42:Root[0000, 0]@0..100#ROOT2024 + LITERAL Float 3.14f64 42:Root[0000, 0]@0..100#ROOT2024 + PUNCH - [alone] 42:Root[0000, 0]@0..100#ROOT2024 + LITERAL Float 3.14f64 42:Root[0000, 0]@0..100#ROOT2024 + LITERAL Float 3.14 42:Root[0000, 0]@0..100#ROOT2024 + PUNCH - [alone] 42:Root[0000, 0]@0..100#ROOT2024 + LITERAL Float 3.14 42:Root[0000, 0]@0..100#ROOT2024 + LITERAL Integer 123i64 42:Root[0000, 0]@0..100#ROOT2024 + PUNCH - [alone] 42:Root[0000, 0]@0..100#ROOT2024 + LITERAL Integer 123i64 42:Root[0000, 0]@0..100#ROOT2024 + LITERAL Integer 123 42:Root[0000, 0]@0..100#ROOT2024 + PUNCH - [alone] 42:Root[0000, 0]@0..100#ROOT2024 + LITERAL Integer 123 42:Root[0000, 0]@0..100#ROOT2024"#]], ); } @@ -296,13 +296,13 @@ fn test_fn_like_mk_idents() { IDENT standard 1 IDENT r#raw 1"#]], expect![[r#" - SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024 + SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024 - SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024 - IDENT standard 42:2@0..100#ROOT2024 - IDENT r#raw 42:2@0..100#ROOT2024"#]], + SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024 + IDENT standard 42:Root[0000, 0]@0..100#ROOT2024 + IDENT r#raw 42:Root[0000, 0]@0..100#ROOT2024"#]], ); } @@ -358,51 +358,51 @@ fn test_fn_like_macro_clone_literals() { PUNCH , [alone] 1 LITERAL CStr null 1"#]], expect![[r#" - SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024 - LITERAL Integer 1u16 42:2@0..4#ROOT2024 - PUNCH , [alone] 42:2@4..5#ROOT2024 - LITERAL Integer 2_u32 42:2@6..11#ROOT2024 - PUNCH , [alone] 42:2@11..12#ROOT2024 - PUNCH - [alone] 42:2@13..14#ROOT2024 - LITERAL Integer 4i64 42:2@14..18#ROOT2024 - PUNCH , [alone] 42:2@18..19#ROOT2024 - LITERAL Float 3.14f32 42:2@20..27#ROOT2024 - PUNCH , [alone] 42:2@27..28#ROOT2024 - LITERAL Str hello bridge 42:2@29..43#ROOT2024 - PUNCH , [alone] 42:2@43..44#ROOT2024 - LITERAL Str suffixedsuffix 42:2@45..61#ROOT2024 - PUNCH , [alone] 42:2@61..62#ROOT2024 - LITERAL StrRaw(2) raw 42:2@63..73#ROOT2024 - PUNCH , [alone] 42:2@73..74#ROOT2024 - LITERAL Char a 42:2@75..78#ROOT2024 - PUNCH , [alone] 42:2@78..79#ROOT2024 - LITERAL Byte b 42:2@80..84#ROOT2024 - PUNCH , [alone] 42:2@84..85#ROOT2024 - LITERAL CStr null 42:2@86..93#ROOT2024 - - - - SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024 - LITERAL Integer 1u16 42:2@0..4#ROOT2024 - PUNCH , [alone] 42:2@4..5#ROOT2024 - LITERAL Integer 2_u32 42:2@6..11#ROOT2024 - PUNCH , [alone] 42:2@11..12#ROOT2024 - PUNCH - [alone] 42:2@13..14#ROOT2024 - LITERAL Integer 4i64 42:2@14..18#ROOT2024 - PUNCH , [alone] 42:2@18..19#ROOT2024 - LITERAL Float 3.14f32 42:2@20..27#ROOT2024 - PUNCH , [alone] 42:2@27..28#ROOT2024 - LITERAL Str hello bridge 42:2@29..43#ROOT2024 - PUNCH , [alone] 42:2@43..44#ROOT2024 - LITERAL Str suffixedsuffix 42:2@45..61#ROOT2024 - PUNCH , [alone] 42:2@61..62#ROOT2024 - LITERAL StrRaw(2) raw 42:2@63..73#ROOT2024 - PUNCH , [alone] 42:2@73..74#ROOT2024 - LITERAL Char a 42:2@75..78#ROOT2024 - PUNCH , [alone] 42:2@78..79#ROOT2024 - LITERAL Byte b 42:2@80..84#ROOT2024 - PUNCH , [alone] 42:2@84..85#ROOT2024 - LITERAL CStr null 42:2@86..93#ROOT2024"#]], + SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024 + LITERAL Integer 1u16 42:Root[0000, 0]@0..4#ROOT2024 + PUNCH , [alone] 42:Root[0000, 0]@4..5#ROOT2024 + LITERAL Integer 2_u32 42:Root[0000, 0]@6..11#ROOT2024 + PUNCH , [alone] 42:Root[0000, 0]@11..12#ROOT2024 + PUNCH - [alone] 42:Root[0000, 0]@13..14#ROOT2024 + LITERAL Integer 4i64 42:Root[0000, 0]@14..18#ROOT2024 + PUNCH , [alone] 42:Root[0000, 0]@18..19#ROOT2024 + LITERAL Float 3.14f32 42:Root[0000, 0]@20..27#ROOT2024 + PUNCH , [alone] 42:Root[0000, 0]@27..28#ROOT2024 + LITERAL Str hello bridge 42:Root[0000, 0]@29..43#ROOT2024 + PUNCH , [alone] 42:Root[0000, 0]@43..44#ROOT2024 + LITERAL Str suffixedsuffix 42:Root[0000, 0]@45..61#ROOT2024 + PUNCH , [alone] 42:Root[0000, 0]@61..62#ROOT2024 + LITERAL StrRaw(2) raw 42:Root[0000, 0]@63..73#ROOT2024 + PUNCH , [alone] 42:Root[0000, 0]@73..74#ROOT2024 + LITERAL Char a 42:Root[0000, 0]@75..78#ROOT2024 + PUNCH , [alone] 42:Root[0000, 0]@78..79#ROOT2024 + LITERAL Byte b 42:Root[0000, 0]@80..84#ROOT2024 + PUNCH , [alone] 42:Root[0000, 0]@84..85#ROOT2024 + LITERAL CStr null 42:Root[0000, 0]@86..93#ROOT2024 + + + + SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024 + LITERAL Integer 1u16 42:Root[0000, 0]@0..4#ROOT2024 + PUNCH , [alone] 42:Root[0000, 0]@4..5#ROOT2024 + LITERAL Integer 2_u32 42:Root[0000, 0]@6..11#ROOT2024 + PUNCH , [alone] 42:Root[0000, 0]@11..12#ROOT2024 + PUNCH - [alone] 42:Root[0000, 0]@13..14#ROOT2024 + LITERAL Integer 4i64 42:Root[0000, 0]@14..18#ROOT2024 + PUNCH , [alone] 42:Root[0000, 0]@18..19#ROOT2024 + LITERAL Float 3.14f32 42:Root[0000, 0]@20..27#ROOT2024 + PUNCH , [alone] 42:Root[0000, 0]@27..28#ROOT2024 + LITERAL Str hello bridge 42:Root[0000, 0]@29..43#ROOT2024 + PUNCH , [alone] 42:Root[0000, 0]@43..44#ROOT2024 + LITERAL Str suffixedsuffix 42:Root[0000, 0]@45..61#ROOT2024 + PUNCH , [alone] 42:Root[0000, 0]@61..62#ROOT2024 + LITERAL StrRaw(2) raw 42:Root[0000, 0]@63..73#ROOT2024 + PUNCH , [alone] 42:Root[0000, 0]@73..74#ROOT2024 + LITERAL Char a 42:Root[0000, 0]@75..78#ROOT2024 + PUNCH , [alone] 42:Root[0000, 0]@78..79#ROOT2024 + LITERAL Byte b 42:Root[0000, 0]@80..84#ROOT2024 + PUNCH , [alone] 42:Root[0000, 0]@84..85#ROOT2024 + LITERAL CStr null 42:Root[0000, 0]@86..93#ROOT2024"#]], ); } @@ -440,33 +440,33 @@ fn test_fn_like_macro_negative_literals() { PUNCH - [alone] 1 LITERAL Float 2.7 1"#]], expect![[r#" - SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024 - PUNCH - [alone] 42:2@0..1#ROOT2024 - LITERAL Integer 1u16 42:2@1..5#ROOT2024 - PUNCH , [alone] 42:2@5..6#ROOT2024 - PUNCH - [alone] 42:2@7..8#ROOT2024 - LITERAL Integer 2_u32 42:2@9..14#ROOT2024 - PUNCH , [alone] 42:2@14..15#ROOT2024 - PUNCH - [alone] 42:2@16..17#ROOT2024 - LITERAL Float 3.14f32 42:2@17..24#ROOT2024 - PUNCH , [alone] 42:2@24..25#ROOT2024 - PUNCH - [alone] 42:2@26..27#ROOT2024 - LITERAL Float 2.7 42:2@28..31#ROOT2024 - - - - SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024 - PUNCH - [alone] 42:2@0..1#ROOT2024 - LITERAL Integer 1u16 42:2@1..5#ROOT2024 - PUNCH , [alone] 42:2@5..6#ROOT2024 - PUNCH - [alone] 42:2@7..8#ROOT2024 - LITERAL Integer 2_u32 42:2@9..14#ROOT2024 - PUNCH , [alone] 42:2@14..15#ROOT2024 - PUNCH - [alone] 42:2@16..17#ROOT2024 - LITERAL Float 3.14f32 42:2@17..24#ROOT2024 - PUNCH , [alone] 42:2@24..25#ROOT2024 - PUNCH - [alone] 42:2@26..27#ROOT2024 - LITERAL Float 2.7 42:2@28..31#ROOT2024"#]], + SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024 + PUNCH - [alone] 42:Root[0000, 0]@0..1#ROOT2024 + LITERAL Integer 1u16 42:Root[0000, 0]@1..5#ROOT2024 + PUNCH , [alone] 42:Root[0000, 0]@5..6#ROOT2024 + PUNCH - [alone] 42:Root[0000, 0]@7..8#ROOT2024 + LITERAL Integer 2_u32 42:Root[0000, 0]@9..14#ROOT2024 + PUNCH , [alone] 42:Root[0000, 0]@14..15#ROOT2024 + PUNCH - [alone] 42:Root[0000, 0]@16..17#ROOT2024 + LITERAL Float 3.14f32 42:Root[0000, 0]@17..24#ROOT2024 + PUNCH , [alone] 42:Root[0000, 0]@24..25#ROOT2024 + PUNCH - [alone] 42:Root[0000, 0]@26..27#ROOT2024 + LITERAL Float 2.7 42:Root[0000, 0]@28..31#ROOT2024 + + + + SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024 + PUNCH - [alone] 42:Root[0000, 0]@0..1#ROOT2024 + LITERAL Integer 1u16 42:Root[0000, 0]@1..5#ROOT2024 + PUNCH , [alone] 42:Root[0000, 0]@5..6#ROOT2024 + PUNCH - [alone] 42:Root[0000, 0]@7..8#ROOT2024 + LITERAL Integer 2_u32 42:Root[0000, 0]@9..14#ROOT2024 + PUNCH , [alone] 42:Root[0000, 0]@14..15#ROOT2024 + PUNCH - [alone] 42:Root[0000, 0]@16..17#ROOT2024 + LITERAL Float 3.14f32 42:Root[0000, 0]@17..24#ROOT2024 + PUNCH , [alone] 42:Root[0000, 0]@24..25#ROOT2024 + PUNCH - [alone] 42:Root[0000, 0]@26..27#ROOT2024 + LITERAL Float 2.7 42:Root[0000, 0]@28..31#ROOT2024"#]], ); } @@ -496,21 +496,21 @@ fn test_attr_macro() { LITERAL Str #[attr_error(some arguments)] mod m {} 1 PUNCH ; [alone] 1"#]], expect![[r#" - SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024 - IDENT mod 42:2@0..3#ROOT2024 - IDENT m 42:2@4..5#ROOT2024 - SUBTREE {} 42:2@6..7#ROOT2024 42:2@7..8#ROOT2024 - - SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024 - IDENT some 42:2@0..4#ROOT2024 - IDENT arguments 42:2@5..14#ROOT2024 - - SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024 - IDENT compile_error 42:2@0..100#ROOT2024 - PUNCH ! [alone] 42:2@0..100#ROOT2024 - SUBTREE () 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024 - LITERAL Str #[attr_error(some arguments)] mod m {} 42:2@0..100#ROOT2024 - PUNCH ; [alone] 42:2@0..100#ROOT2024"#]], + SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024 + IDENT mod 42:Root[0000, 0]@0..3#ROOT2024 + IDENT m 42:Root[0000, 0]@4..5#ROOT2024 + SUBTREE {} 42:Root[0000, 0]@6..7#ROOT2024 42:Root[0000, 0]@7..8#ROOT2024 + + SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024 + IDENT some 42:Root[0000, 0]@0..4#ROOT2024 + IDENT arguments 42:Root[0000, 0]@5..14#ROOT2024 + + SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024 + IDENT compile_error 42:Root[0000, 0]@0..100#ROOT2024 + PUNCH ! [alone] 42:Root[0000, 0]@0..100#ROOT2024 + SUBTREE () 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024 + LITERAL Str #[attr_error(some arguments)] mod m {} 42:Root[0000, 0]@0..100#ROOT2024 + PUNCH ; [alone] 42:Root[0000, 0]@0..100#ROOT2024"#]], ); } diff --git a/crates/proc-macro-srv/src/tests/utils.rs b/crates/proc-macro-srv/src/tests/utils.rs index a0a45b269e4a..e0a69608decd 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 b3b401c3db44..966962bab381 100644 --- a/crates/span/Cargo.toml +++ b/crates/span/Cargo.toml @@ -22,6 +22,9 @@ vfs.workspace = true syntax.workspace = true stdx.workspace = true +[dev-dependencies] +syntax.workspace = true + [features] default = ["salsa"] diff --git a/crates/span/src/ast_id.rs b/crates/span/src/ast_id.rs index 228fba1fa096..51a693ca011b 100644 --- a/crates/span/src/ast_id.rs +++ b/crates/span/src/ast_id.rs @@ -4,137 +4,534 @@ //! Specifically, it enumerates all items in a file and uses position of a an //! item as an ID. That way, id's don't change unless the set of items itself //! changes. +//! +//! These IDs are tricky. If one of them invalidates, its interned ID invalidates, +//! and this can cause *a lot* to be recomputed. For example, if you invalidate the ID +//! of a struct, and that struct has an impl (any impl!) this will cause the `Self` +//! type of the impl to invalidate, which will cause the all impls queries to be +//! invalidated, which will cause every trait solve query in this crate *and* all +//! transitive reverse dependencies to be invalidated, which is pretty much the worst +//! thing that can happen incrementality wise. +//! +//! So we want these IDs to stay as stable as possible. For top-level items, we store +//! their kind and name, which should be unique, but since they can still not be, we +//! also store an index disambiguator. For nested items, we also store the ID of their +//! parent. For macro calls, we store the macro name and an index. There aren't usually +//! a lot of macro calls in item position, and invalidation in bodies is not much of +//! a problem, so this should be enough. use std::{ any::type_name, fmt, - hash::{BuildHasher, BuildHasherDefault, Hash, Hasher}, + hash::{BuildHasher, Hash, Hasher}, marker::PhantomData, }; use la_arena::{Arena, Idx, RawIdx}; -use rustc_hash::FxHasher; -use syntax::{AstNode, AstPtr, SyntaxNode, SyntaxNodePtr, ast}; +use rustc_hash::{FxBuildHasher, FxHashMap}; +use syntax::{ + AstNode, AstPtr, SyntaxKind, SyntaxNode, SyntaxNodePtr, + ast::{self, HasName}, + match_ast, +}; + +// The first index is always the root node's AstId +/// The root ast id always points to the encompassing file, using this in spans is discouraged as +/// any range relative to it will be effectively absolute, ruining the entire point of anchored +/// relative text ranges. +pub const ROOT_ERASED_FILE_AST_ID: ErasedFileAstId = + ErasedFileAstId(pack_hash_index_and_kind(0, 0, ErasedFileAstIdKind::Root as u32)); + +/// ErasedFileAstId used as the span for syntax node fixups. Any Span containing this file id is to be +/// considered fake. +pub const FIXUP_ERASED_FILE_AST_ID_MARKER: ErasedFileAstId = + ErasedFileAstId(pack_hash_index_and_kind(0, 0, ErasedFileAstIdKind::Fixup as u32)); -/// See crates\hir-expand\src\ast_id_map.rs /// This is a type erased FileAstId. -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, Hash)] pub struct ErasedFileAstId(u32); +impl fmt::Debug for ErasedFileAstId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let kind = self.kind(); + macro_rules! kind { + ($($kind:ident),* $(,)?) => { + if false { + // Ensure we covered all variants. + match ErasedFileAstIdKind::Root { + $( ErasedFileAstIdKind::$kind => {} )* + } + unreachable!() + } + $( else if kind == ErasedFileAstIdKind::$kind as u32 { + stringify!($kind) + } )* + else { + "Unknown" + } + }; + } + let kind = kind!( + Root, + Enum, + Struct, + Union, + ExternCrate, + MacroDef, + MacroRules, + Module, + Static, + Trait, + TraitAlias, + Variant, + Const, + Fn, + MacroCall, + TypeAlias, + ExternBlock, + Use, + Impl, + BlockExpr, + Fixup, + ); + if f.alternate() { + write!(f, "{kind}[{:04X}, {}]", self.hash_value(), self.index()) + } else { + f.debug_struct("ErasedFileAstId") + .field("kind", &format_args!("{kind}")) + .field("index", &self.index()) + .field("hash", &format_args!("{:04X}", self.hash_value())) + .finish() + } + } +} + +#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] +enum ErasedFileAstIdKind { + Root, + // The following are associated with `ErasedHasNameFileAstId`. + Enum, + Struct, + Union, + ExternCrate, + MacroDef, + MacroRules, + Module, + Static, + Trait, + TraitAlias, + // Until here associated with `ErasedHasNameFileAstId`. + // The following are associated with `ErasedAssocItemFileAstId`. + Variant, + Const, + Fn, + MacroCall, + TypeAlias, + // Until here associated with `ErasedAssocItemFileAstId`. + // Extern blocks don't really have any identifying property unfortunately. + ExternBlock, + // FIXME: If we store the final `UseTree` instead of the top-level `Use`, we can store its name, + // and be way more granular for incrementality, at the expense of increased memory usage. + // Use IDs aren't used a lot. The main thing that stores them is the def map. So everything that + // uses the def map will be invalidated. That includes infers, and so is pretty bad, but our + // def map incrementality story is pretty bad anyway and needs to be improved (see + // https://rust-lang.zulipchat.com/#narrow/channel/185405-t-compiler.2Frust-analyzer/topic/.60infer.60.20queries.20and.20splitting.20.60DefMap.60). + // So I left this as-is for now, as the def map improvement should also mitigate this. + Use, + /// Associated with [`ImplFileAstId`]. + Impl, + /// Associated with [`BlockExprFileAstId`]. + BlockExpr, + /// Keep this last. + Fixup, +} + +// First hash, then index, then kind. +const HASH_BITS: u32 = 16; +const INDEX_BITS: u32 = 11; +const KIND_BITS: u32 = 5; +const _: () = assert!(ErasedFileAstIdKind::Fixup as u32 <= ((1 << KIND_BITS) - 1)); +const _: () = assert!(HASH_BITS + INDEX_BITS + KIND_BITS == u32::BITS); + +#[inline] +const fn u16_hash(hash: u64) -> u16 { + // We do basically the same as `FxHasher`. We don't use rustc-hash and truncate because the + // higher bits have more entropy, but unlike rustc-hash we don't rotate because it rotates + // for hashmaps that just use the low bits, but we compare all bits. + const K: u16 = 0xecc5; + let (part1, part2, part3, part4) = + (hash as u16, (hash >> 16) as u16, (hash >> 32) as u16, (hash >> 48) as u16); + part1 + .wrapping_add(part2) + .wrapping_mul(K) + .wrapping_add(part3) + .wrapping_mul(K) + .wrapping_add(part4) + .wrapping_mul(K) +} + +#[inline] +const fn pack_hash_index_and_kind(hash: u16, index: u32, kind: u32) -> u32 { + (hash as u32) | (index << HASH_BITS) | (kind << (HASH_BITS + INDEX_BITS)) +} + impl ErasedFileAstId { - pub const fn into_raw(self) -> u32 { - self.0 + #[inline] + fn hash_value(self) -> u16 { + self.0 as u16 } - pub const fn from_raw(u32: u32) -> Self { - Self(u32) + + #[inline] + fn index(self) -> u32 { + (self.0 << KIND_BITS) >> (HASH_BITS + KIND_BITS) } -} -impl fmt::Display for ErasedFileAstId { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) + #[inline] + fn kind(self) -> u32 { + self.0 >> (HASH_BITS + INDEX_BITS) } -} -impl fmt::Debug for ErasedFileAstId { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) + + fn ast_id_for( + node: &SyntaxNode, + index_map: &mut ErasedAstIdNextIndexMap, + parent: Option<&ErasedFileAstId>, + ) -> Option { + // Blocks are deliberately not here - we only want to allocate a block if it contains items. + has_name_ast_id(node, index_map) + .or_else(|| assoc_item_ast_id(node, index_map, parent)) + .or_else(|| extern_block_ast_id(node, index_map)) + .or_else(|| use_ast_id(node, index_map)) + .or_else(|| impl_ast_id(node, index_map)) + } + + fn should_alloc(node: &SyntaxNode) -> bool { + should_alloc_has_name(node) + || should_alloc_assoc_item(node) + || ast::ExternBlock::can_cast(node.kind()) + || ast::Use::can_cast(node.kind()) + || ast::Impl::can_cast(node.kind()) + } + + #[inline] + pub fn into_raw(self) -> u32 { + self.0 + } + + #[inline] + pub fn from_raw(v: u32) -> Self { + Self(v) } } +pub trait AstIdNode: AstNode {} + /// `AstId` points to an AST node in a specific file. -pub struct FileAstId { +pub struct FileAstId { raw: ErasedFileAstId, - covariant: PhantomData N>, + _marker: PhantomData N>, } -impl Clone for FileAstId { +/// Traits are manually implemented because `derive` adds redundant bounds. +impl Clone for FileAstId { + #[inline] fn clone(&self) -> FileAstId { *self } } -impl Copy for FileAstId {} +impl Copy for FileAstId {} -impl PartialEq for FileAstId { +impl PartialEq for FileAstId { fn eq(&self, other: &Self) -> bool { self.raw == other.raw } } -impl Eq for FileAstId {} -impl Hash for FileAstId { +impl Eq for FileAstId {} +impl Hash for FileAstId { fn hash(&self, hasher: &mut H) { self.raw.hash(hasher); } } -impl fmt::Debug for FileAstId { +impl fmt::Debug for FileAstId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "FileAstId::<{}>({})", type_name::(), self.raw) + write!(f, "FileAstId::<{}>({:?})", type_name::(), self.raw) } } -impl FileAstId { +impl FileAstId { // Can't make this a From implementation because of coherence + #[inline] pub fn upcast(self) -> FileAstId where N: Into, { - FileAstId { raw: self.raw, covariant: PhantomData } + FileAstId { raw: self.raw, _marker: PhantomData } } + #[inline] pub fn erase(self) -> ErasedFileAstId { self.raw } } -pub trait AstIdNode: AstNode {} -macro_rules! register_ast_id_node { +#[derive(Hash)] +struct ErasedHasNameFileAstId<'a> { + kind: SyntaxKind, + name: &'a str, +} + +/// This holds the ast ID for variants too (they're a kind of assoc item). +#[derive(Hash)] +struct ErasedAssocItemFileAstId<'a> { + /// Subtle: items in `extern` blocks **do not** store the ID of the extern block here. + /// Instead this is left empty. The reason is that `ExternBlockFileAstId` is pretty unstable + /// (it contains only an index), and extern blocks don't introduce a new scope, so storing + /// the extern block ID will do more harm to incrementality than help. + parent: Option, + properties: ErasedHasNameFileAstId<'a>, +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +struct ImplFileAstId<'a> { + /// This can be `None` if the `Self` type is not a named type, or if it is inside a macro call. + self_ty_name: Option<&'a str>, + /// This can be `None` if this is an inherent impl, or if the trait name is inside a macro call. + trait_name: Option<&'a str>, +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +struct BlockExprFileAstId { + parent: Option, +} + +impl AstIdNode for ast::ExternBlock {} + +fn extern_block_ast_id( + node: &SyntaxNode, + index_map: &mut ErasedAstIdNextIndexMap, +) -> Option { + if ast::ExternBlock::can_cast(node.kind()) { + Some(index_map.new_id(ErasedFileAstIdKind::ExternBlock, ())) + } else { + None + } +} + +impl AstIdNode for ast::Use {} + +fn use_ast_id( + node: &SyntaxNode, + index_map: &mut ErasedAstIdNextIndexMap, +) -> Option { + if ast::Use::can_cast(node.kind()) { + Some(index_map.new_id(ErasedFileAstIdKind::Use, ())) + } else { + None + } +} + +impl AstIdNode for ast::Impl {} + +fn impl_ast_id( + node: &SyntaxNode, + index_map: &mut ErasedAstIdNextIndexMap, +) -> Option { + if let Some(node) = ast::Impl::cast(node.clone()) { + let type_as_name = |ty: Option| match ty? { + ast::Type::PathType(it) => Some(it.path()?.segment()?.name_ref()?), + _ => None, + }; + let self_ty_name = type_as_name(node.self_ty()); + let trait_name = type_as_name(node.trait_()); + let data = ImplFileAstId { + self_ty_name: self_ty_name.as_ref().map(|it| it.text_non_mutable()), + trait_name: trait_name.as_ref().map(|it| it.text_non_mutable()), + }; + Some(index_map.new_id(ErasedFileAstIdKind::Impl, data)) + } else { + None + } +} + +// Blocks aren't `AstIdNode`s deliberately, because unlike other nodes, not all blocks get their own +// ast id, only if they have items. To account for that we have a different, fallible, API for blocks. +// impl !AstIdNode for ast::BlockExpr {} + +fn block_expr_ast_id( + node: &SyntaxNode, + index_map: &mut ErasedAstIdNextIndexMap, + parent: Option<&ErasedFileAstId>, +) -> Option { + if ast::BlockExpr::can_cast(node.kind()) { + Some( + index_map.new_id( + ErasedFileAstIdKind::BlockExpr, + BlockExprFileAstId { parent: parent.copied() }, + ), + ) + } else { + None + } +} + +#[derive(Default)] +struct ErasedAstIdNextIndexMap(FxHashMap<(ErasedFileAstIdKind, u16), u32>); + +impl ErasedAstIdNextIndexMap { + #[inline] + fn new_id(&mut self, kind: ErasedFileAstIdKind, data: impl Hash) -> ErasedFileAstId { + let hash = FxBuildHasher.hash_one(&data); + let initial_hash = u16_hash(hash); + // Even though 2^INDEX_BITS=2048 items with the same hash seems like a lot, + // it could happen with macro calls or `use`s in macro-generated files. So we want + // to handle it gracefully. We just increment the hash. + let mut hash = initial_hash; + let index = loop { + match self.0.entry((kind, hash)) { + std::collections::hash_map::Entry::Occupied(mut entry) => { + let i = entry.get_mut(); + if *i < ((1 << INDEX_BITS) - 1) { + *i += 1; + break *i; + } + } + std::collections::hash_map::Entry::Vacant(entry) => { + entry.insert(0); + break 0; + } + } + hash = hash.wrapping_add(1); + if hash == initial_hash { + // That's 2^27=134,217,728 items! + panic!("you have way too many items in the same file!"); + } + }; + let kind = kind as u32; + ErasedFileAstId(pack_hash_index_and_kind(hash, index, kind)) + } +} + +macro_rules! register_enum_ast_id { (impl AstIdNode for $($ident:ident),+ ) => { $( impl AstIdNode for ast::$ident {} )+ - fn should_alloc_id(kind: syntax::SyntaxKind) -> bool { - $( - ast::$ident::can_cast(kind) - )||+ + }; +} +register_enum_ast_id! { + impl AstIdNode for + Item, AnyHasGenericParams, Adt, Macro, + AssocItem +} + +macro_rules! register_has_name_ast_id { + (impl AstIdNode for $($ident:ident = $name_method:ident),+ ) => { + $( + impl AstIdNode for ast::$ident {} + )+ + + fn has_name_ast_id(node: &SyntaxNode, index_map: &mut ErasedAstIdNextIndexMap) -> Option { + let kind = node.kind(); + match_ast! { + match node { + $( + ast::$ident(node) => { + let name = node.$name_method(); + let name = name.as_ref().map_or("", |it| it.text_non_mutable()); + let result = ErasedHasNameFileAstId { + kind, + name, + }; + Some(index_map.new_id(ErasedFileAstIdKind::$ident, result)) + }, + )* + _ => None, + } + } + } + + fn should_alloc_has_name(node: &SyntaxNode) -> bool { + let kind = node.kind(); + false $( || ast::$ident::can_cast(kind) )* } }; } -register_ast_id_node! { +register_has_name_ast_id! { impl AstIdNode for - Item, AnyHasGenericParams, - Adt, - Enum, - Variant, - Struct, - Union, - AssocItem, - Const, - Fn, - MacroCall, - TypeAlias, - ExternBlock, - ExternCrate, - Impl, - Macro, - MacroDef, - MacroRules, - Module, - Static, - Trait, - TraitAlias, - Use, - BlockExpr, ConstArg + Enum = name, + Struct = name, + Union = name, + ExternCrate = name_ref, + MacroDef = name, + MacroRules = name, + Module = name, + Static = name, + Trait = name, + TraitAlias = name +} + +macro_rules! register_assoc_item_ast_id { + (impl AstIdNode for $($ident:ident = $name_callback:expr),+ ) => { + $( + impl AstIdNode for ast::$ident {} + )+ + + fn assoc_item_ast_id( + node: &SyntaxNode, + index_map: &mut ErasedAstIdNextIndexMap, + parent: Option<&ErasedFileAstId>, + ) -> Option { + let kind = node.kind(); + match_ast! { + match node { + $( + ast::$ident(node) => { + let name = $name_callback(node); + let name = name.as_ref().map_or("", |it| it.text_non_mutable()); + let properties = ErasedHasNameFileAstId { + kind, + name, + }; + let result = ErasedAssocItemFileAstId { + parent: parent.copied(), + properties, + }; + Some(index_map.new_id(ErasedFileAstIdKind::$ident, result)) + }, + )* + _ => None, + } + } + } + + fn should_alloc_assoc_item(node: &SyntaxNode) -> bool { + let kind = node.kind(); + false $( || ast::$ident::can_cast(kind) )* + } + }; +} +register_assoc_item_ast_id! { + impl AstIdNode for + Variant = |it: ast::Variant| it.name(), + Const = |it: ast::Const| it.name(), + Fn = |it: ast::Fn| it.name(), + MacroCall = |it: ast::MacroCall| it.path().and_then(|path| path.segment()?.name_ref()), + TypeAlias = |it: ast::TypeAlias| it.name() } /// Maps items' `SyntaxNode`s to `ErasedFileAstId`s and back. #[derive(Default)] pub struct AstIdMap { - /// Maps stable id to unstable ptr. - arena: Arena, - /// Reverse: map ptr to id. - map: hashbrown::HashTable>, + /// An arena of the ptrs and their associated ID. + arena: Arena<(SyntaxNodePtr, ErasedFileAstId)>, + /// Map ptr to id. + ptr_map: hashbrown::HashTable, + /// Map id to ptr. + id_map: hashbrown::HashTable, } +type ArenaId = Idx<(SyntaxNodePtr, ErasedFileAstId)>; + impl fmt::Debug for AstIdMap { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("AstIdMap").field("arena", &self.arena).finish() @@ -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{:?}", + FileAstId { raw: self.erased_ast_id(ptr), _marker: PhantomData } + } + + /// Blocks may not be allocated (if they have no items), so they have a different API. + pub fn ast_id_for_ptr_for_block( + &self, + ptr: AstPtr, + ) -> Option> { + let ptr = ptr.syntax_node_ptr(); + self.try_erased_ast_id(ptr).map(|raw| FileAstId { raw, _marker: PhantomData }) + } + + fn erased_ast_id(&self, ptr: SyntaxNodePtr) -> ErasedFileAstId { + self.try_erased_ast_id(ptr).unwrap_or_else(|| { + panic!( + "Can't find SyntaxNodePtr {:?} in AstIdMap:\n{:?}", ptr, self.arena.iter().map(|(_id, i)| i).collect::>(), - ), - } + ) + }) } - pub fn get(&self, id: FileAstId) -> AstPtr { - AstPtr::try_from_raw(self.arena[Idx::from_raw(RawIdx::from_u32(id.raw.into_raw()))]) - .unwrap() + fn try_erased_ast_id(&self, ptr: SyntaxNodePtr) -> Option { + let hash = hash_ptr(&ptr); + let idx = *self.ptr_map.find(hash, |&idx| self.arena[idx].0 == ptr)?; + Some(self.arena[idx].1) } - pub fn get_erased(&self, id: ErasedFileAstId) -> SyntaxNodePtr { - self.arena[Idx::from_raw(RawIdx::from_u32(id.into_raw()))] + // Don't bound on `AstIdNode` here, because `BlockExpr`s are also valid here (`ast::BlockExpr` + // doesn't always have a matching `FileAstId`, but a `FileAstId` always has + // a matching node). + pub fn get(&self, id: FileAstId) -> AstPtr { + let ptr = self.get_erased(id.raw); + AstPtr::try_from_raw(ptr) + .unwrap_or_else(|| panic!("AstIdMap node mismatch with node `{ptr:?}`")) } - fn erased_ast_id(&self, item: &SyntaxNode) -> ErasedFileAstId { - let ptr = SyntaxNodePtr::new(item); - let hash = hash_ptr(&ptr); - match self.map.find(hash, |&idx| self.arena[idx] == ptr) { - Some(&idx) => ErasedFileAstId(idx.into_raw().into_u32()), + pub fn get_erased(&self, id: ErasedFileAstId) -> SyntaxNodePtr { + let hash = hash_ast_id(&id); + match self.id_map.find(hash, |&idx| self.arena[idx].1 == id) { + Some(&idx) => self.arena[idx].0, None => panic!( - "Can't find {:?} in AstIdMap:\n{:?}\n source text: {}", - item, + "Can't find ast id {:?} in AstIdMap:\n{:?}", + id, self.arena.iter().map(|(_id, i)| i).collect::>(), - item ), } } - - fn alloc(&mut self, item: &SyntaxNode) -> ErasedFileAstId { - ErasedFileAstId(self.arena.alloc(SyntaxNodePtr::new(item)).into_raw().into_u32()) - } } +#[inline] fn hash_ptr(ptr: &SyntaxNodePtr) -> u64 { - BuildHasherDefault::::default().hash_one(ptr) -} - -#[derive(Copy, Clone, PartialEq, Eq)] -enum TreeOrder { - BreadthFirst, - DepthFirst, -} - -/// Walks the subtree in bdfs order, calling `f` for each node. What is bdfs -/// order? It is a mix of breadth-first and depth first orders. Nodes for which -/// `f` returns [`TreeOrder::BreadthFirst`] are visited breadth-first, all the other nodes are explored -/// [`TreeOrder::DepthFirst`]. -/// -/// In other words, the size of the bfs queue is bound by the number of "true" -/// nodes. -fn bdfs(node: &SyntaxNode, mut f: impl FnMut(SyntaxNode) -> TreeOrder) { - let mut curr_layer = vec![node.clone()]; - let mut next_layer = vec![]; - while !curr_layer.is_empty() { - curr_layer.drain(..).for_each(|node| { - let mut preorder = node.preorder(); - while let Some(event) = preorder.next() { - match event { - syntax::WalkEvent::Enter(node) => { - if f(node.clone()) == TreeOrder::BreadthFirst { - next_layer.extend(node.children()); - preorder.skip_subtree(); - } - } - syntax::WalkEvent::Leave(_) => {} - } + FxBuildHasher.hash_one(ptr) +} + +#[inline] +fn hash_ast_id(ptr: &ErasedFileAstId) -> u64 { + FxBuildHasher.hash_one(ptr) +} + +#[cfg(test)] +mod tests { + use syntax::{AstNode, Edition, SourceFile, SyntaxKind, SyntaxNodePtr, WalkEvent, ast}; + + use crate::AstIdMap; + + #[test] + fn check_all_nodes() { + let syntax = SourceFile::parse( + r#" +extern crate foo; +fn foo() { + union U {} +} +struct S; +macro_rules! m {} +macro m2() {} +trait Trait {} +impl Trait for S {} +impl S {} +impl m!() {} +impl m2!() for m!() {} +type T = i32; +enum E { + V1(), + V2 {}, + V3, +} +struct S; // duplicate +extern "C" { + static S: i32; +} +static mut S: i32 = 0; +const FOO: i32 = 0; + "#, + Edition::CURRENT, + ) + .syntax_node(); + let ast_id_map = AstIdMap::from_source(&syntax); + for node in syntax.preorder() { + let WalkEvent::Enter(node) = node else { continue }; + if !matches!( + node.kind(), + SyntaxKind::EXTERN_CRATE + | SyntaxKind::FN + | SyntaxKind::UNION + | SyntaxKind::STRUCT + | SyntaxKind::MACRO_RULES + | SyntaxKind::MACRO_DEF + | SyntaxKind::MACRO_CALL + | SyntaxKind::TRAIT + | SyntaxKind::IMPL + | SyntaxKind::TYPE_ALIAS + | SyntaxKind::ENUM + | SyntaxKind::VARIANT + | SyntaxKind::EXTERN_BLOCK + | SyntaxKind::STATIC + | SyntaxKind::CONST + ) { + continue; } - }); - std::mem::swap(&mut curr_layer, &mut next_layer); + let ptr = SyntaxNodePtr::new(&node); + let ast_id = ast_id_map.erased_ast_id(ptr); + let turn_back = ast_id_map.get_erased(ast_id); + assert_eq!(ptr, turn_back); + } + } + + #[test] + fn different_names_get_different_hashes() { + let syntax = SourceFile::parse( + r#" +fn foo() {} +fn bar() {} + "#, + Edition::CURRENT, + ) + .syntax_node(); + let ast_id_map = AstIdMap::from_source(&syntax); + let fns = syntax.descendants().filter_map(ast::Fn::cast).collect::>(); + let [foo_fn, bar_fn] = fns.as_slice() else { + panic!("not exactly 2 functions"); + }; + let foo_fn_id = ast_id_map.ast_id(foo_fn); + let bar_fn_id = ast_id_map.ast_id(bar_fn); + assert_ne!(foo_fn_id.raw.hash_value(), bar_fn_id.raw.hash_value(), "hashes are equal"); + } + + #[test] + fn different_parents_get_different_hashes() { + let syntax = SourceFile::parse( + r#" +fn foo() { + m!(); +} +fn bar() { + m!(); +} + "#, + Edition::CURRENT, + ) + .syntax_node(); + let ast_id_map = AstIdMap::from_source(&syntax); + let macro_calls = syntax.descendants().filter_map(ast::MacroCall::cast).collect::>(); + let [macro_call_foo, macro_call_bar] = macro_calls.as_slice() else { + panic!("not exactly 2 macro calls"); + }; + let macro_call_foo_id = ast_id_map.ast_id(macro_call_foo); + let macro_call_bar_id = ast_id_map.ast_id(macro_call_bar); + assert_ne!( + macro_call_foo_id.raw.hash_value(), + macro_call_bar_id.raw.hash_value(), + "hashes are equal" + ); + } + + #[test] + fn blocks_with_no_items_have_no_id() { + let syntax = SourceFile::parse( + r#" +fn foo() { + let foo = 1; + bar(foo); +} + "#, + Edition::CURRENT, + ) + .syntax_node(); + let ast_id_map = AstIdMap::from_source(&syntax); + let block = syntax.descendants().find_map(ast::BlockExpr::cast).expect("no block"); + assert!(ast_id_map.ast_id_for_block(&block).is_none()); } } diff --git a/crates/span/src/lib.rs b/crates/span/src/lib.rs index f81648ac42c5..b81d08eed6d8 100644 --- a/crates/span/src/lib.rs +++ b/crates/span/src/lib.rs @@ -6,7 +6,10 @@ mod hygiene; mod map; pub use self::{ - ast_id::{AstIdMap, AstIdNode, ErasedFileAstId, FileAstId}, + ast_id::{ + AstIdMap, AstIdNode, ErasedFileAstId, FIXUP_ERASED_FILE_AST_ID_MARKER, FileAstId, + ROOT_ERASED_FILE_AST_ID, + }, hygiene::{SyntaxContext, Transparency}, map::{RealSpanMap, SpanMap}, }; @@ -15,19 +18,6 @@ pub use syntax::Edition; pub use text_size::{TextRange, TextSize}; pub use vfs::FileId; -// The first index is always the root node's AstId -/// The root ast id always points to the encompassing file, using this in spans is discouraged as -/// any range relative to it will be effectively absolute, ruining the entire point of anchored -/// relative text ranges. -pub const ROOT_ERASED_FILE_AST_ID: ErasedFileAstId = ErasedFileAstId::from_raw(0); - -/// FileId used as the span for syntax node fixups. Any Span containing this file id is to be -/// considered fake. -pub const FIXUP_ERASED_FILE_AST_ID_MARKER: ErasedFileAstId = - // we pick the second to last for this in case we ever consider making this a NonMaxU32, this - // is required to be stable for the proc-macro-server - ErasedFileAstId::from_raw(!0 - 1); - pub type Span = SpanData; impl Span { @@ -60,7 +50,7 @@ impl fmt::Debug for SpanData { if f.alternate() { fmt::Debug::fmt(&self.anchor.file_id.file_id().index(), f)?; f.write_char(':')?; - fmt::Debug::fmt(&self.anchor.ast_id.into_raw(), f)?; + write!(f, "{:#?}", self.anchor.ast_id)?; f.write_char('@')?; fmt::Debug::fmt(&self.range, f)?; f.write_char('#')?; @@ -85,7 +75,7 @@ impl fmt::Display for Span { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&self.anchor.file_id.file_id().index(), f)?; f.write_char(':')?; - fmt::Debug::fmt(&self.anchor.ast_id.into_raw(), f)?; + write!(f, "{:#?}", self.anchor.ast_id)?; f.write_char('@')?; fmt::Debug::fmt(&self.range, f)?; f.write_char('#')?; @@ -101,7 +91,7 @@ pub struct SpanAnchor { impl fmt::Debug for SpanAnchor { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("SpanAnchor").field(&self.file_id).field(&self.ast_id.into_raw()).finish() + f.debug_tuple("SpanAnchor").field(&self.file_id).field(&self.ast_id).finish() } } diff --git a/crates/span/src/map.rs b/crates/span/src/map.rs index cc7a886643a9..f58201793da2 100644 --- a/crates/span/src/map.rs +++ b/crates/span/src/map.rs @@ -169,7 +169,7 @@ impl fmt::Display for RealSpanMap { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { writeln!(f, "RealSpanMap({:?}):", self.file_id)?; for span in self.pairs.iter() { - writeln!(f, "{}: {}", u32::from(span.0), span.1.into_raw())?; + writeln!(f, "{}: {:#?}", u32::from(span.0), span.1)?; } Ok(()) } diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs index dcf853427e53..f5530c5fffd2 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 1a3cc8232c584289111c8eba8357f1eb08721dd0 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Wed, 21 May 2025 13:13:34 +0300 Subject: [PATCH 2/6] 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 | 158 ++++--- 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 | 10 +- 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 | 212 ++++++---- 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/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 +- 36 files changed, 983 insertions(+), 958 deletions(-) diff --git a/crates/hir-def/src/attr.rs b/crates/hir-def/src/attr.rs index bb6222b1d464..a7328809a823 100644 --- a/crates/hir-def/src/attr.rs +++ b/crates/hir-def/src/attr.rs @@ -14,6 +14,7 @@ use intern::{Symbol, sym}; use la_arena::{ArenaMap, Idx, RawIdx}; use mbe::DelimiterKind; use rustc_abi::ReprOptions; +use span::AstIdNode; use syntax::{ AstPtr, ast::{self, HasAttrs}, @@ -22,10 +23,10 @@ use triomphe::Arc; use tt::iter::{TtElement, TtIter}; use crate::{ - AdtId, AttrDefId, GenericParamId, HasModule, ItemTreeLoc, LocalFieldId, Lookup, MacroId, + AdtId, AstIdLoc, AttrDefId, GenericParamId, HasModule, LocalFieldId, Lookup, MacroId, VariantId, db::DefDatabase, - item_tree::{AttrOwner, FieldParent, ItemTreeNode}, + item_tree::AttrOwner, lang_item::LangItem, nameres::{ModuleOrigin, ModuleSource}, src::{HasChildSource, HasSource}, @@ -42,6 +43,15 @@ pub struct AttrsWithOwner { } impl Attrs { + pub fn new( + db: &dyn DefDatabase, + owner: &dyn ast::HasAttrs, + span_map: SpanMapRef<'_>, + cfg_options: &CfgOptions, + ) -> Self { + Attrs(RawAttrs::new_expanded(db, owner, span_map, cfg_options)) + } + pub fn get(&self, id: AttrId) -> Option<&Attr> { (**self).iter().find(|attr| attr.id == id) } @@ -94,44 +104,64 @@ impl Attrs { v: VariantId, ) -> Arc> { let _p = tracing::info_span!("fields_attrs_query").entered(); - // FIXME: There should be some proper form of mapping between item tree field ids and hir field ids let mut res = ArenaMap::default(); - let item_tree; - let (parent, fields, krate) = match v { + let (fields, file_id, krate) = match v { VariantId::EnumVariantId(it) => { let loc = it.lookup(db); let krate = loc.parent.lookup(db).container.krate; - item_tree = loc.id.item_tree(db); - let variant = &item_tree[loc.id.value]; - (FieldParent::EnumVariant(loc.id.value), &variant.fields, krate) + let source = loc.source(db); + (source.value.field_list(), source.file_id, krate) } VariantId::StructId(it) => { let loc = it.lookup(db); let krate = loc.container.krate; - item_tree = loc.id.item_tree(db); - let struct_ = &item_tree[loc.id.value]; - (FieldParent::Struct(loc.id.value), &struct_.fields, krate) + let source = loc.source(db); + (source.value.field_list(), source.file_id, krate) } VariantId::UnionId(it) => { let loc = it.lookup(db); let krate = loc.container.krate; - item_tree = loc.id.item_tree(db); - let union_ = &item_tree[loc.id.value]; - (FieldParent::Union(loc.id.value), &union_.fields, krate) + let source = loc.source(db); + ( + source.value.record_field_list().map(ast::FieldList::RecordFieldList), + source.file_id, + krate, + ) } }; + let Some(fields) = fields else { + return Arc::new(res); + }; let cfg_options = krate.cfg_options(db); - - let mut idx = 0; - for (id, _field) in fields.iter().enumerate() { - let attrs = item_tree.attrs(db, krate, AttrOwner::make_field_indexed(parent, id)); - if attrs.is_cfg_enabled(cfg_options) { - res.insert(Idx::from_raw(RawIdx::from(idx)), attrs); - idx += 1; + let span_map = db.span_map(file_id); + + match fields { + ast::FieldList::RecordFieldList(fields) => { + let mut idx = 0; + for field in fields.fields() { + let attrs = + Attrs(RawAttrs::new_expanded(db, &field, span_map.as_ref(), cfg_options)); + if attrs.is_cfg_enabled(cfg_options).is_ok() { + res.insert(Idx::from_raw(RawIdx::from(idx)), attrs); + idx += 1; + } + } + } + ast::FieldList::TupleFieldList(fields) => { + let mut idx = 0; + for field in fields.fields() { + let attrs = + Attrs(RawAttrs::new_expanded(db, &field, span_map.as_ref(), cfg_options)); + if attrs.is_cfg_enabled(cfg_options).is_ok() { + res.insert(Idx::from_raw(RawIdx::from(idx)), attrs); + idx += 1; + } + } } } + res.shrink_to_fit(); Arc::new(res) } } @@ -167,11 +197,10 @@ impl Attrs { } #[inline] - pub(crate) fn is_cfg_enabled(&self, cfg_options: &CfgOptions) -> bool { - match self.cfg() { - None => true, - Some(cfg) => cfg_options.check(&cfg) != Some(false), - } + pub(crate) fn is_cfg_enabled(&self, cfg_options: &CfgOptions) -> Result<(), CfgExpr> { + self.cfgs().try_for_each(|cfg| { + if cfg_options.check(&cfg) != Some(false) { Ok(()) } else { Err(cfg) } + }) } #[inline] @@ -488,12 +517,12 @@ impl AttrsWithOwner { pub(crate) fn attrs_query(db: &dyn DefDatabase, def: AttrDefId) -> Attrs { let _p = tracing::info_span!("attrs_query").entered(); // FIXME: this should use `Trace` to avoid duplication in `source_map` below - let raw_attrs = match def { + match def { AttrDefId::ModuleId(module) => { let def_map = module.def_map(db); let mod_data = &def_map[module.local_id]; - match mod_data.origin { + let raw_attrs = match mod_data.origin { ModuleOrigin::File { definition, declaration_tree_id, .. } => { let decl_attrs = declaration_tree_id .item_tree(db) @@ -515,34 +544,33 @@ impl AttrsWithOwner { let tree = db.block_item_tree(id); tree.raw_attrs(AttrOwner::TopLevel).clone() } - } - } - AttrDefId::FieldId(it) => { - return db.fields_attrs(it.parent)[it.local_id].clone(); + }; + Attrs::expand_cfg_attr(db, module.krate, raw_attrs) } - AttrDefId::EnumVariantId(it) => attrs_from_item_tree_loc(db, it), + AttrDefId::FieldId(it) => db.fields_attrs(it.parent)[it.local_id].clone(), + AttrDefId::EnumVariantId(it) => attrs_from_ast_id_loc(db, it), AttrDefId::AdtId(it) => match it { - AdtId::StructId(it) => attrs_from_item_tree_loc(db, it), - AdtId::EnumId(it) => attrs_from_item_tree_loc(db, it), - AdtId::UnionId(it) => attrs_from_item_tree_loc(db, it), + AdtId::StructId(it) => attrs_from_ast_id_loc(db, it), + AdtId::EnumId(it) => attrs_from_ast_id_loc(db, it), + AdtId::UnionId(it) => attrs_from_ast_id_loc(db, it), }, - AttrDefId::TraitId(it) => attrs_from_item_tree_loc(db, it), - AttrDefId::TraitAliasId(it) => attrs_from_item_tree_loc(db, it), + AttrDefId::TraitId(it) => attrs_from_ast_id_loc(db, it), + AttrDefId::TraitAliasId(it) => attrs_from_ast_id_loc(db, it), AttrDefId::MacroId(it) => match it { - MacroId::Macro2Id(it) => attrs_from_item_tree_loc(db, it), - MacroId::MacroRulesId(it) => attrs_from_item_tree_loc(db, it), - MacroId::ProcMacroId(it) => attrs_from_item_tree_loc(db, it), + MacroId::Macro2Id(it) => attrs_from_ast_id_loc(db, it), + MacroId::MacroRulesId(it) => attrs_from_ast_id_loc(db, it), + MacroId::ProcMacroId(it) => attrs_from_ast_id_loc(db, it), }, - AttrDefId::ImplId(it) => attrs_from_item_tree_loc(db, it), - AttrDefId::ConstId(it) => attrs_from_item_tree_loc(db, it), - AttrDefId::StaticId(it) => attrs_from_item_tree_loc(db, it), - AttrDefId::FunctionId(it) => attrs_from_item_tree_loc(db, it), - AttrDefId::TypeAliasId(it) => attrs_from_item_tree_loc(db, it), + AttrDefId::ImplId(it) => attrs_from_ast_id_loc(db, it), + AttrDefId::ConstId(it) => attrs_from_ast_id_loc(db, it), + AttrDefId::StaticId(it) => attrs_from_ast_id_loc(db, it), + AttrDefId::FunctionId(it) => attrs_from_ast_id_loc(db, it), + AttrDefId::TypeAliasId(it) => attrs_from_ast_id_loc(db, it), AttrDefId::GenericParamId(it) => match it { GenericParamId::ConstParamId(it) => { let src = it.parent().child_source(db); // FIXME: We should be never getting `None` here. - return Attrs(match src.value.get(it.local_id()) { + Attrs(match src.value.get(it.local_id()) { Some(val) => RawAttrs::new_expanded( db, val, @@ -550,12 +578,12 @@ impl AttrsWithOwner { def.krate(db).cfg_options(db), ), None => RawAttrs::EMPTY, - }); + }) } GenericParamId::TypeParamId(it) => { let src = it.parent().child_source(db); // FIXME: We should be never getting `None` here. - return Attrs(match src.value.get(it.local_id()) { + Attrs(match src.value.get(it.local_id()) { Some(val) => RawAttrs::new_expanded( db, val, @@ -563,12 +591,12 @@ impl AttrsWithOwner { def.krate(db).cfg_options(db), ), None => RawAttrs::EMPTY, - }); + }) } GenericParamId::LifetimeParamId(it) => { let src = it.parent.child_source(db); // FIXME: We should be never getting `None` here. - return Attrs(match src.value.get(it.local_id) { + Attrs(match src.value.get(it.local_id) { Some(val) => RawAttrs::new_expanded( db, val, @@ -576,16 +604,13 @@ impl AttrsWithOwner { def.krate(db).cfg_options(db), ), None => RawAttrs::EMPTY, - }); + }) } }, - AttrDefId::ExternBlockId(it) => attrs_from_item_tree_loc(db, it), - AttrDefId::ExternCrateId(it) => attrs_from_item_tree_loc(db, it), - AttrDefId::UseId(it) => attrs_from_item_tree_loc(db, it), - }; - - let attrs = raw_attrs.expand_cfg_attr(db, def.krate(db)); - Attrs(attrs) + AttrDefId::ExternBlockId(it) => attrs_from_ast_id_loc(db, it), + AttrDefId::ExternCrateId(it) => attrs_from_ast_id_loc(db, it), + AttrDefId::UseId(it) => attrs_from_ast_id_loc(db, it), + } } pub fn source_map(&self, db: &dyn DefDatabase) -> AttrSourceMap { @@ -787,14 +812,15 @@ fn any_has_attrs<'db>( id.lookup(db).source(db).map(ast::AnyHasAttrs::new) } -fn attrs_from_item_tree_loc<'db, N: ItemTreeNode>( +fn attrs_from_ast_id_loc<'db, N: AstIdNode + HasAttrs>( db: &(dyn DefDatabase + 'db), - lookup: impl Lookup>, -) -> RawAttrs { - let id = lookup.lookup(db).item_tree_id(); - let tree = id.item_tree(db); - let attr_owner = N::attr_owner(id.value); - tree.raw_attrs(attr_owner).clone() + lookup: impl Lookup + HasModule>, +) -> Attrs { + let loc = lookup.lookup(db); + let source = loc.source(db); + let span_map = db.span_map(source.file_id); + let cfg_options = loc.krate(db).cfg_options(db); + Attrs(RawAttrs::new_expanded(db, &source.value, span_map.as_ref(), cfg_options)) } pub(crate) fn fields_attrs_source_map( diff --git a/crates/hir-def/src/db.rs b/crates/hir-def/src/db.rs index 4a9a3b12cfab..362c0daa9bbe 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 3823fb5a1e75..23b9712d1e6c 100644 --- a/crates/hir-def/src/expr_store/expander.rs +++ b/crates/hir-def/src/expr_store/expander.rs @@ -6,6 +6,7 @@ use base_db::Crate; use cfg::CfgOptions; use drop_bomb::DropBomb; use hir_expand::AstId; +use hir_expand::span_map::SpanMapRef; use hir_expand::{ ExpandError, ExpandErrorKind, ExpandResult, HirFileId, InFile, Lookup, MacroCallId, eager::EagerCallBackFn, mod_path::ModPath, span_map::SpanMap, @@ -223,9 +224,15 @@ impl Expander { } } + #[inline] pub(super) fn ast_id_map(&self) -> &AstIdMap { &self.ast_id_map } + + #[inline] + pub(super) fn span_map(&self) -> SpanMapRef<'_> { + self.span_map.as_ref() + } } #[derive(Debug)] diff --git a/crates/hir-def/src/expr_store/lower.rs b/crates/hir-def/src/expr_store/lower.rs index b7a482a85dbb..89eeaf00bc3d 100644 --- a/crates/hir-def/src/expr_store/lower.rs +++ b/crates/hir-def/src/expr_store/lower.rs @@ -10,9 +10,10 @@ use std::mem; use cfg::CfgOptions; use either::Either; use hir_expand::{ - HirFileId, InFile, Lookup, MacroDefId, + HirFileId, InFile, MacroDefId, mod_path::tool_path, name::{AsName, Name}, + span_map::SpanMapRef, }; use intern::{Symbol, sym}; use rustc_hash::FxHashMap; @@ -30,8 +31,8 @@ use triomphe::Arc; use tt::TextRange; use crate::{ - AdtId, BlockId, BlockLoc, DefWithBodyId, FunctionId, GenericDefId, ImplId, ItemTreeLoc, - MacroId, ModuleDefId, ModuleId, TraitAliasId, TraitId, TypeAliasId, UnresolvedMacro, + AdtId, BlockId, BlockLoc, DefWithBodyId, FunctionId, GenericDefId, ImplId, MacroId, + ModuleDefId, ModuleId, TraitAliasId, TraitId, TypeAliasId, UnresolvedMacro, builtin_type::BuiltinUint, db::DefDatabase, expr_store::{ @@ -564,6 +565,11 @@ impl ExprCollector<'_> { } } + #[inline] + pub(crate) fn span_map(&self) -> SpanMapRef<'_> { + self.expander.span_map() + } + pub fn lower_lifetime_ref(&mut self, lifetime: ast::Lifetime) -> LifetimeRefId { // FIXME: Keyword check? let lifetime_ref = match &*lifetime.text() { @@ -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 f12a9b7a5445..7b452721dfe2 100644 --- a/crates/hir-def/src/expr_store/pretty.rs +++ b/crates/hir-def/src/expr_store/pretty.rs @@ -9,9 +9,10 @@ use std::{ use hir_expand::{Lookup, mod_path::PathKind}; use itertools::Itertools; use span::Edition; +use syntax::ast::HasName; use crate::{ - AdtId, DefWithBodyId, GenericDefId, ItemTreeLoc, TypeParamId, VariantId, + AdtId, DefWithBodyId, GenericDefId, TypeParamId, VariantId, expr_store::path::{GenericArg, GenericArgs}, hir::{ Array, BindingAnnotation, CaptureBy, ClosureKind, Literal, Movability, Statement, @@ -19,6 +20,7 @@ use crate::{ }, lang_item::LangItemTarget, signatures::{FnFlags, FunctionSignature, StructSignature}, + src::HasSource, type_ref::{ConstRef, LifetimeRef, Mutability, TraitBoundModifier, TypeBound, UseArgRef}, }; use crate::{LifetimeParamId, signatures::StructFlags}; @@ -48,6 +50,17 @@ pub enum LineFormat { Indentation, } +fn item_name(db: &dyn DefDatabase, id: Id, default: &str) -> String +where + Id: Lookup, + Loc: HasSource, + Loc::Value: ast::HasName, +{ + let loc = id.lookup(db); + let source = loc.source(db); + source.value.name().map_or_else(|| default.to_owned(), |name| name.to_string()) +} + pub fn print_body_hir( db: &dyn DefDatabase, body: &Body, @@ -55,31 +68,14 @@ pub fn print_body_hir( edition: Edition, ) -> String { let header = match owner { - DefWithBodyId::FunctionId(it) => { - it.lookup(db).id.resolved(db, |it| format!("fn {}", it.name.display(db, edition))) - } - DefWithBodyId::StaticId(it) => it - .lookup(db) - .id - .resolved(db, |it| format!("static {} = ", it.name.display(db, edition))), - DefWithBodyId::ConstId(it) => it.lookup(db).id.resolved(db, |it| { - format!( - "const {} = ", - match &it.name { - Some(name) => name.display(db, edition).to_string(), - None => "_".to_owned(), - } - ) - }), - DefWithBodyId::VariantId(it) => { - let loc = it.lookup(db); - let enum_loc = loc.parent.lookup(db); - format!( - "enum {}::{}", - enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db, edition), - loc.id.item_tree(db)[loc.id.value].name.display(db, edition), - ) - } + DefWithBodyId::FunctionId(it) => format!("fn {}", item_name(db, it, "")), + DefWithBodyId::StaticId(it) => format!("static {} = ", item_name(db, it, "")), + DefWithBodyId::ConstId(it) => format!("const {} = ", item_name(db, it, "_")), + DefWithBodyId::VariantId(it) => format!( + "enum {}::{}", + item_name(db, it.lookup(db).parent, ""), + item_name(db, it, "") + ), }; let mut p = Printer { @@ -116,22 +112,13 @@ pub fn print_body_hir( pub fn print_variant_body_hir(db: &dyn DefDatabase, owner: VariantId, edition: Edition) -> String { let header = match owner { - VariantId::StructId(it) => { - it.lookup(db).id.resolved(db, |it| format!("struct {}", it.name.display(db, edition))) - } - VariantId::EnumVariantId(enum_variant_id) => { - let loc = enum_variant_id.lookup(db); - let enum_loc = loc.parent.lookup(db); - format!( - "enum {}::{}", - enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db, edition), - loc.id.item_tree(db)[loc.id.value].name.display(db, edition), - ) - } - VariantId::UnionId(union_id) => union_id - .lookup(db) - .id - .resolved(db, |it| format!("union {}", it.name.display(db, edition))), + VariantId::StructId(it) => format!("struct {}", item_name(db, it, "")), + VariantId::EnumVariantId(it) => format!( + "enum {}::{}", + item_name(db, it.lookup(db).parent, ""), + item_name(db, it, "") + ), + VariantId::UnionId(it) => format!("union {}", item_name(db, it, "")), }; let fields = db.variant_fields(owner); @@ -1089,10 +1076,7 @@ impl Printer<'_> { w!(self, "builtin#lang("); macro_rules! write_name { ($it:ident) => {{ - let loc = $it.lookup(self.db); - let tree = loc.item_tree_id().item_tree(self.db); - let name = &tree[loc.id.value].name; - w!(self, "{}", name.display(self.db, self.edition)); + w!(self, "{}", item_name(self.db, $it, "")); }}; } match *it { diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs index 1b97eb72b6f2..65dc35337a52 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 b490e1683c01..57765427693d 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 51172c0a1ee3..8ff14751c671 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 b9ac3aa73129..7a85e8d175e6 100644 --- a/crates/hir-def/src/item_tree/tests.rs +++ b/crates/hir-def/src/item_tree/tests.rs @@ -140,23 +140,23 @@ enum E { pub(self) 0, ); - // AstId: Union[83AF, 0] + // AstId: Union[2DBB, 0] pub(self) union Ize { pub(self) a, pub(self) b, } // AstId: Enum[7FF8, 0] - pub(self) enum E - // AstId: Variant[CA8D, 0] + pub(self) enum E { + // AstId: Variant[C717, 0] #[doc = " comment on Unit"] Unit, - // AstId: Variant[F89F, 0] + // AstId: Variant[AEAB, 0] #[doc = " comment on Tuple"] Tuple( pub(self) 0, ), - // AstId: Variant[C117, 0] + // AstId: Variant[4B1B, 0] Struct { #[doc = " comment on a: u8"] pub(self) a, diff --git a/crates/hir-def/src/lang_item.rs b/crates/hir-def/src/lang_item.rs index 4ad44775ea14..1614ef0da435 100644 --- a/crates/hir-def/src/lang_item.rs +++ b/crates/hir-def/src/lang_item.rs @@ -125,7 +125,7 @@ pub fn crate_lang_items(db: &dyn DefDatabase, krate: Crate) -> Option { lang_items.collect_lang_item(db, e, LangItemTarget::EnumId); - db.enum_variants(e).variants.iter().for_each(|&(id, _)| { + db.enum_variants(e).variants.iter().for_each(|&(id, _, _)| { lang_items.collect_lang_item(db, id, LangItemTarget::EnumVariant); }); } diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs index b41ff026bcaa..df22ac7093af 100644 --- a/crates/hir-def/src/lib.rs +++ b/crates/hir-def/src/lib.rs @@ -74,12 +74,11 @@ use hir_expand::{ name::Name, proc_macro::{CustomProcMacroExpander, ProcMacroKind}, }; -use item_tree::ExternBlock; use la_arena::Idx; use nameres::DefMap; use span::{AstIdNode, Edition, FileAstId, SyntaxContext}; use stdx::impl_from; -use syntax::ast; +use syntax::{AstNode, ast}; pub use hir_expand::{Intern, Lookup, tt}; @@ -88,10 +87,6 @@ use crate::{ builtin_type::BuiltinType, db::DefDatabase, hir::generics::{LocalLifetimeParamId, LocalTypeOrConstParamId}, - item_tree::{ - Const, Enum, ExternCrate, Function, Impl, ItemTreeId, ItemTreeNode, Macro2, MacroRules, - Static, Struct, Trait, TraitAlias, TypeAlias, Union, Use, Variant, - }, nameres::{LocalDefMap, block_def_map, crate_def_map, crate_local_def_map}, signatures::VariantFields, }; @@ -113,70 +108,110 @@ pub struct ImportPathConfig { } #[derive(Debug)] -pub struct ItemLoc { +pub struct ItemLoc { pub container: ModuleId, - pub id: ItemTreeId, + pub id: AstId, } -impl Clone for ItemLoc { +impl Clone for ItemLoc { fn clone(&self) -> Self { *self } } -impl Copy for ItemLoc {} +impl Copy for ItemLoc {} -impl PartialEq for ItemLoc { +impl PartialEq for ItemLoc { fn eq(&self, other: &Self) -> bool { self.container == other.container && self.id == other.id } } -impl Eq for ItemLoc {} +impl Eq for ItemLoc {} -impl Hash for ItemLoc { +impl Hash for ItemLoc { fn hash(&self, state: &mut H) { self.container.hash(state); self.id.hash(state); } } +impl HasModule for ItemLoc { + #[inline] + fn module(&self, _db: &dyn DefDatabase) -> ModuleId { + self.container + } +} + #[derive(Debug)] -pub struct AssocItemLoc { +pub struct AssocItemLoc { pub container: ItemContainerId, - pub id: ItemTreeId, + pub id: AstId, } -impl Clone for AssocItemLoc { +impl Clone for AssocItemLoc { fn clone(&self) -> Self { *self } } -impl Copy for AssocItemLoc {} +impl Copy for AssocItemLoc {} -impl PartialEq for AssocItemLoc { +impl PartialEq for AssocItemLoc { fn eq(&self, other: &Self) -> bool { self.container == other.container && self.id == other.id } } -impl Eq for AssocItemLoc {} +impl Eq for AssocItemLoc {} -impl Hash for AssocItemLoc { +impl Hash for AssocItemLoc { fn hash(&self, state: &mut H) { self.container.hash(state); self.id.hash(state); } } -pub trait ItemTreeLoc { +impl HasModule for AssocItemLoc { + #[inline] + fn module(&self, db: &dyn DefDatabase) -> ModuleId { + self.container.module(db) + } +} + +pub trait AstIdLoc { type Container; - type Id; - fn item_tree_id(&self) -> ItemTreeId; + type Ast: AstNode; + fn ast_id(&self) -> AstId; fn container(&self) -> Self::Container; } +impl AstIdLoc for ItemLoc { + type Container = ModuleId; + type Ast = N; + #[inline] + fn ast_id(&self) -> AstId { + self.id + } + #[inline] + fn container(&self) -> Self::Container { + self.container + } +} + +impl AstIdLoc for AssocItemLoc { + type Container = ItemContainerId; + type Ast = N; + #[inline] + fn ast_id(&self) -> AstId { + self.id + } + #[inline] + fn container(&self) -> Self::Container { + self.container + } +} + macro_rules! impl_intern { ($id:ident, $loc:ident, $intern:ident, $lookup:ident) => { impl_intern_key!($id, $loc); @@ -186,74 +221,68 @@ macro_rules! impl_intern { macro_rules! impl_loc { ($loc:ident, $id:ident: $id_ty:ident, $container:ident: $container_type:ident) => { - impl ItemTreeLoc for $loc { + impl AstIdLoc for $loc { type Container = $container_type; - type Id = $id_ty; - fn item_tree_id(&self) -> ItemTreeId { + type Ast = ast::$id_ty; + fn ast_id(&self) -> AstId { self.$id } fn container(&self) -> Self::Container { self.$container } } + + impl HasModule for $loc { + #[inline] + fn module(&self, db: &dyn DefDatabase) -> ModuleId { + self.$container.module(db) + } + } }; } -type FunctionLoc = AssocItemLoc; +type FunctionLoc = AssocItemLoc; impl_intern!(FunctionId, FunctionLoc, intern_function, lookup_intern_function); -impl_loc!(FunctionLoc, id: Function, container: ItemContainerId); -type StructLoc = ItemLoc; +type StructLoc = ItemLoc; impl_intern!(StructId, StructLoc, intern_struct, lookup_intern_struct); -impl_loc!(StructLoc, id: Struct, container: ModuleId); -pub type UnionLoc = ItemLoc; +pub type UnionLoc = ItemLoc; impl_intern!(UnionId, UnionLoc, intern_union, lookup_intern_union); -impl_loc!(UnionLoc, id: Union, container: ModuleId); -pub type EnumLoc = ItemLoc; +pub type EnumLoc = ItemLoc; impl_intern!(EnumId, EnumLoc, intern_enum, lookup_intern_enum); -impl_loc!(EnumLoc, id: Enum, container: ModuleId); -type ConstLoc = AssocItemLoc; +type ConstLoc = AssocItemLoc; impl_intern!(ConstId, ConstLoc, intern_const, lookup_intern_const); -impl_loc!(ConstLoc, id: Const, container: ItemContainerId); -pub type StaticLoc = AssocItemLoc; +pub type StaticLoc = AssocItemLoc; impl_intern!(StaticId, StaticLoc, intern_static, lookup_intern_static); -impl_loc!(StaticLoc, id: Static, container: ItemContainerId); -pub type TraitLoc = ItemLoc; +pub type TraitLoc = ItemLoc; impl_intern!(TraitId, TraitLoc, intern_trait, lookup_intern_trait); -impl_loc!(TraitLoc, id: Trait, container: ModuleId); -pub type TraitAliasLoc = ItemLoc; +pub type TraitAliasLoc = ItemLoc; impl_intern!(TraitAliasId, TraitAliasLoc, intern_trait_alias, lookup_intern_trait_alias); -impl_loc!(TraitAliasLoc, id: TraitAlias, container: ModuleId); -type TypeAliasLoc = AssocItemLoc; +type TypeAliasLoc = AssocItemLoc; impl_intern!(TypeAliasId, TypeAliasLoc, intern_type_alias, lookup_intern_type_alias); -impl_loc!(TypeAliasLoc, id: TypeAlias, container: ItemContainerId); -type ImplLoc = ItemLoc; +type ImplLoc = ItemLoc; impl_intern!(ImplId, ImplLoc, intern_impl, lookup_intern_impl); -impl_loc!(ImplLoc, id: Impl, container: ModuleId); -type UseLoc = ItemLoc; +type UseLoc = ItemLoc; impl_intern!(UseId, UseLoc, intern_use, lookup_intern_use); -impl_loc!(UseLoc, id: Use, container: ModuleId); -type ExternCrateLoc = ItemLoc; +type ExternCrateLoc = ItemLoc; impl_intern!(ExternCrateId, ExternCrateLoc, intern_extern_crate, lookup_intern_extern_crate); -impl_loc!(ExternCrateLoc, id: ExternCrate, container: ModuleId); -type ExternBlockLoc = ItemLoc; +type ExternBlockLoc = ItemLoc; impl_intern!(ExternBlockId, ExternBlockLoc, intern_extern_block, lookup_intern_extern_block); -impl_loc!(ExternBlockLoc, id: ExternBlock, container: ModuleId); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct EnumVariantLoc { - pub id: ItemTreeId, + pub id: AstId, pub parent: EnumId, pub index: u32, } @@ -262,18 +291,18 @@ impl_loc!(EnumVariantLoc, id: Variant, parent: EnumId); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct Macro2Loc { pub container: ModuleId, - pub id: ItemTreeId, + pub id: AstId, pub expander: MacroExpander, pub allow_internal_unsafe: bool, pub edition: Edition, } impl_intern!(Macro2Id, Macro2Loc, intern_macro2, lookup_intern_macro2); -impl_loc!(Macro2Loc, id: Macro2, container: ModuleId); +impl_loc!(Macro2Loc, id: MacroDef, container: ModuleId); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct MacroRulesLoc { pub container: ModuleId, - pub id: ItemTreeId, + pub id: AstId, pub expander: MacroExpander, pub flags: MacroRulesLocFlags, pub edition: Edition, @@ -301,13 +330,13 @@ pub enum MacroExpander { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct ProcMacroLoc { pub container: CrateRootModuleId, - pub id: ItemTreeId, + pub id: AstId, pub expander: CustomProcMacroExpander, pub kind: ProcMacroKind, pub edition: Edition, } impl_intern!(ProcMacroId, ProcMacroLoc, intern_proc_macro, lookup_intern_proc_macro); -impl_loc!(ProcMacroLoc, id: Function, container: CrateRootModuleId); +impl_loc!(ProcMacroLoc, id: Fn, container: CrateRootModuleId); #[derive(Debug, Hash, PartialEq, Eq, Clone)] pub struct BlockLoc { @@ -338,6 +367,18 @@ impl CrateRootModuleId { } } +impl HasModule for CrateRootModuleId { + #[inline] + fn module(&self, _db: &dyn DefDatabase) -> ModuleId { + ModuleId { krate: self.krate, block: None, local_id: DefMap::ROOT } + } + + #[inline] + fn krate(&self, _db: &dyn DefDatabase) -> Crate { + self.krate + } +} + impl PartialEq for CrateRootModuleId { fn eq(&self, other: &ModuleId) -> bool { other.block.is_none() && other.local_id == DefMap::ROOT && self.krate == other.krate @@ -466,6 +507,13 @@ impl ModuleId { } } +impl HasModule for ModuleId { + #[inline] + fn module(&self, _db: &dyn DefDatabase) -> ModuleId { + *self + } +} + /// An ID of a module, **local** to a `DefMap`. pub type LocalModuleId = Idx; @@ -642,15 +690,10 @@ impl GeneralConstId { pub fn name(self, db: &dyn DefDatabase) -> String { match self { GeneralConstId::StaticId(it) => { - let loc = it.lookup(db); - let tree = loc.item_tree_id().item_tree(db); - let name = tree[loc.id.value].name.display(db, Edition::CURRENT); - name.to_string() + db.static_signature(it).name.display(db, Edition::CURRENT).to_string() } GeneralConstId::ConstId(const_id) => { - let loc = const_id.lookup(db); - let tree = loc.item_tree_id().item_tree(db); - tree[loc.id.value].name.as_ref().map_or_else( + db.const_signature(const_id).name.as_ref().map_or_else( || "_".to_owned(), |name| name.display(db, Edition::CURRENT).to_string(), ) @@ -768,8 +811,8 @@ impl GenericDefId { GenericDefId::TraitId(it) => file_id_and_params_of_item_loc(db, it), GenericDefId::TraitAliasId(it) => file_id_and_params_of_item_loc(db, it), GenericDefId::ImplId(it) => file_id_and_params_of_item_loc(db, it), - GenericDefId::ConstId(it) => (it.lookup(db).id.file_id(), None), - GenericDefId::StaticId(it) => (it.lookup(db).id.file_id(), None), + GenericDefId::ConstId(it) => (it.lookup(db).id.file_id, None), + GenericDefId::StaticId(it) => (it.lookup(db).id.file_id, None), } } @@ -935,9 +978,9 @@ impl VariantId { pub fn file_id(self, db: &dyn DefDatabase) -> HirFileId { match self { - VariantId::EnumVariantId(it) => it.lookup(db).id.file_id(), - VariantId::StructId(it) => it.lookup(db).id.file_id(), - VariantId::UnionId(it) => it.lookup(db).id.file_id(), + VariantId::EnumVariantId(it) => it.lookup(db).id.file_id, + VariantId::StructId(it) => it.lookup(db).id.file_id, + VariantId::UnionId(it) => it.lookup(db).id.file_id, } } @@ -977,7 +1020,7 @@ pub trait HasModule { impl HasModule for ItemId where - N: ItemTreeNode, + N: AstIdNode, ItemId: Lookup> + Copy, { #[inline] @@ -1003,7 +1046,7 @@ where #[inline] fn module_for_assoc_item_loc<'db>( db: &(dyn 'db + DefDatabase), - id: impl Lookup>, + id: impl Lookup>, ) -> ModuleId { id.lookup(db).container.module(db) } diff --git a/crates/hir-def/src/nameres.rs b/crates/hir-def/src/nameres.rs index f337f83156a9..c908e457540b 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 86225d33b4e1..cf123d14f502 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]; - let def = - FunctionLoc { container: self.container, id: ItemTreeId::new(tree_id, id) } - .intern(self.db); - self.items.push((item.name.clone(), def.into())); + ast::AssocItem::Fn(function) => { + let Some(name) = function.name() else { return }; + let ast_id = self.ast_id_map.ast_id(&function); + let def = FunctionLoc { + container: self.container, + id: InFile::new(self.file_id, ast_id), + } + .intern(self.db); + self.items.push((name.as_name(), def.into())); + } + ast::AssocItem::TypeAlias(type_alias) => { + let Some(name) = type_alias.name() else { return }; + let ast_id = self.ast_id_map.ast_id(&type_alias); + let def = TypeAliasLoc { + container: self.container, + id: InFile::new(self.file_id, ast_id), + } + .intern(self.db); + self.items.push((name.as_name(), def.into())); } - AssocItem::TypeAlias(id) => { - let item = &item_tree[id]; + ast::AssocItem::Const(konst) => { + let Some(name) = konst.name() else { return }; + let ast_id = self.ast_id_map.ast_id(&konst); let def = - TypeAliasLoc { container: self.container, id: ItemTreeId::new(tree_id, id) } + ConstLoc { container: self.container, id: InFile::new(self.file_id, ast_id) } .intern(self.db); - self.items.push((item.name.clone(), def.into())); - } - AssocItem::Const(id) => { - let item = &item_tree[id]; - let Some(name) = item.name.clone() else { return }; - let def = ConstLoc { container: self.container, id: ItemTreeId::new(tree_id, id) } - .intern(self.db); - self.items.push((name, def.into())); + self.items.push((name.as_name(), def.into())); } - AssocItem::MacroCall(call) => { - let MacroCall { ast_id, expand_to, ctxt, ref path } = item_tree[call]; + ast::AssocItem::MacroCall(call) => { + let ast_id = self.ast_id_map.ast_id(&call); + let ast_id = InFile::new(self.file_id, ast_id); + let Some(path) = call.path() else { return }; + let range = path.syntax().text_range(); + let Some(path) = ModPath::from_src(self.db, path, &mut |range| { + self.span_map.span_for_range(range).ctx + }) else { + return; + }; + let path = Interned::new(path); + let ctxt = self.span_map.span_for_range(range).ctx; let resolver = |path: &_| { self.def_map @@ -268,10 +303,10 @@ impl<'a> AssocItemCollector<'a> { }; match macro_call_as_call_id( self.db, - InFile::new(tree_id.file_id(), ast_id), - path, + ast_id, + &path, ctxt, - expand_to, + ExpandTo::Items, self.module_id.krate(), resolver, &mut |ptr, call_id| { @@ -281,8 +316,7 @@ impl<'a> AssocItemCollector<'a> { // FIXME: Expansion error? Ok(call_id) => match call_id.value { Some(call_id) => { - self.macro_calls - .push((InFile::new(tree_id.file_id(), ast_id.upcast()), call_id)); + self.macro_calls.push((ast_id.upcast(), call_id)); self.collect_macro_items(call_id); } None => (), @@ -291,11 +325,11 @@ impl<'a> AssocItemCollector<'a> { self.diagnostics.push(DefDiagnostic::unresolved_macro_call( self.module_id.local_id, MacroCallKind::FnLike { - ast_id: InFile::new(tree_id.file_id(), ast_id), - expand_to, + ast_id, + expand_to: ExpandTo::Items, eager: None, }, - Clone::clone(path), + (*path).clone(), )); } } @@ -308,13 +342,29 @@ impl<'a> AssocItemCollector<'a> { tracing::warn!("macro expansion is too deep"); return; } - let tree_id = TreeId::new(macro_call_id.into(), None); - let item_tree = self.db.file_item_tree(macro_call_id.into()); + let (syntax, span_map) = self.db.parse_macro_expansion(macro_call_id).value; + let old_file_id = mem::replace(&mut self.file_id, macro_call_id.into()); + let old_ast_id_map = mem::replace(&mut self.ast_id_map, self.db.ast_id_map(self.file_id)); + let old_span_map = mem::replace(&mut self.span_map, SpanMap::ExpansionSpanMap(span_map)); self.depth += 1; - for item in item_tree.top_level_items().iter().filter_map(ModItem::as_assoc_item) { - self.collect_item(&item_tree, tree_id, item); + + let items = ast::MacroItems::cast(syntax.syntax_node()).expect("not `MacroItems`"); + for item in items.items() { + let item = match item { + ast::Item::Fn(it) => ast::AssocItem::from(it), + ast::Item::Const(it) => it.into(), + ast::Item::TypeAlias(it) => it.into(), + ast::Item::MacroCall(it) => it.into(), + // FIXME: Should error on disallowed item kinds. + _ => continue, + }; + self.collect_item(item); } + self.depth -= 1; + self.file_id = old_file_id; + self.ast_id_map = old_ast_id_map; + self.span_map = old_span_map; } } diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index 350c97c39825..34a129a88eaa 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -9,8 +9,8 @@ use base_db::{BuiltDependency, Crate, CrateOrigin, LangCrateOrigin}; use cfg::{CfgAtom, CfgExpr, CfgOptions}; use either::Either; use hir_expand::{ - EditionedFileId, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId, - MacroDefKind, + EditionedFileId, ErasedAstId, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, + MacroDefId, MacroDefKind, attrs::{Attr, AttrId}, builtin::{find_builtin_attr, find_builtin_derive, find_builtin_macro}, mod_path::{ModPath, PathKind}, @@ -35,9 +35,8 @@ use crate::{ db::DefDatabase, item_scope::{GlobId, ImportId, ImportOrExternCrate, PerNsGlobImports}, item_tree::{ - self, AttrOwner, FieldsShape, FileItemTreeId, ImportAlias, ImportKind, ItemTree, - ItemTreeId, ItemTreeNode, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, TreeId, - UseTreeKind, + self, FieldsShape, FileItemTreeId, ImportAlias, ImportKind, ItemTree, ItemTreeId, + ItemTreeNode, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, TreeId, UseTreeKind, }, macro_call_as_call_id, nameres::{ @@ -141,6 +140,7 @@ struct ImportSource { id: UseId, is_prelude: bool, kind: ImportKind, + item_tree_id: ItemTreeId, } #[derive(Debug, Eq, PartialEq)] @@ -166,7 +166,7 @@ impl Import { path, alias, visibility: visibility.clone(), - source: ImportSource { use_tree: idx, id, is_prelude, kind }, + source: ImportSource { use_tree: idx, id, is_prelude, kind, item_tree_id }, }); }); } @@ -576,13 +576,7 @@ impl DefCollector<'_> { /// use a dummy expander that always errors. This comes with the drawback of macros potentially /// going out of sync with what the build system sees (since we resolve using VFS state, but /// Cargo builds only on-disk files). We could and probably should add diagnostics for that. - fn export_proc_macro( - &mut self, - def: ProcMacroDef, - id: ItemTreeId, - ast_id: AstId, - fn_id: FunctionId, - ) { + fn export_proc_macro(&mut self, def: ProcMacroDef, ast_id: AstId, fn_id: FunctionId) { let kind = def.kind.to_basedb_kind(); let (expander, kind) = match self.proc_macros.iter().find(|(n, _, _)| n == &def.name) { Some(_) @@ -598,7 +592,7 @@ impl DefCollector<'_> { let proc_macro_id = ProcMacroLoc { container: self.def_map.crate_root(), - id, + id: ast_id, expander, kind, edition: self.def_map.data.edition, @@ -866,6 +860,7 @@ impl DefCollector<'_> { kind: kind @ (ImportKind::Plain | ImportKind::TypeOnly), id, use_tree, + item_tree_id, .. } => { let name = match &import.alias { @@ -887,9 +882,33 @@ impl DefCollector<'_> { let imp = ImportOrExternCrate::Import(ImportId { use_: id, idx: use_tree }); tracing::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def); + // `extern crate crate_name` things can be re-exported as `pub use crate_name`. + // But they cannot be re-exported as `pub use self::crate_name`, `pub use crate::crate_name` + // or `pub use ::crate_name`. + // + // This has been historically allowed, but may be not allowed in future + // https://github.com/rust-lang/rust/issues/127909 + if let Some(def) = def.types.as_mut() { + let is_extern_crate_reimport_without_prefix = || { + let Some(ImportOrExternCrate::ExternCrate(_)) = def.import else { + return false; + }; + let item_tree = item_tree_id.item_tree(self.db); + let use_kind = item_tree[item_tree_id.value].use_tree.kind(); + let UseTreeKind::Single { path, .. } = use_kind else { + return false; + }; + matches!(path.kind, PathKind::Plain | PathKind::SELF) + && path.segments().len() < 2 + }; + if is_extern_crate_reimport_without_prefix() { + def.vis = vis; + } + } + self.update(module_id, &[(name.cloned(), def)], vis, Some(imp)); } - ImportSource { kind: ImportKind::Glob, id, is_prelude, use_tree } => { + ImportSource { kind: ImportKind::Glob, id, is_prelude, use_tree, .. } => { tracing::debug!("glob import: {:?}", import); let glob = GlobId { use_: id, idx: use_tree }; match def.take_types() { @@ -978,7 +997,7 @@ impl DefCollector<'_> { .enum_variants(e) .variants .iter() - .map(|&(variant, ref name)| { + .map(|&(variant, ref name, _)| { let res = PerNs::both(variant.into(), variant.into(), vis, None); (Some(name.clone()), res) }) @@ -1150,33 +1169,8 @@ impl DefCollector<'_> { vis: Visibility, def_import_type: Option, ) -> bool { - // `extern crate crate_name` things can be re-exported as `pub use crate_name`. - // But they cannot be re-exported as `pub use self::crate_name`, `pub use crate::crate_name` - // or `pub use ::crate_name`. - // - // This has been historically allowed, but may be not allowed in future - // https://github.com/rust-lang/rust/issues/127909 if let Some(def) = defs.types.as_mut() { - let is_extern_crate_reimport_without_prefix = || { - let Some(ImportOrExternCrate::ExternCrate(_)) = def.import else { - return false; - }; - let Some(ImportOrExternCrate::Import(id)) = def_import_type else { - return false; - }; - let use_id = id.use_.lookup(self.db).id; - let item_tree = use_id.item_tree(self.db); - let use_kind = item_tree[use_id.value].use_tree.kind(); - let UseTreeKind::Single { path, .. } = use_kind else { - return false; - }; - path.segments().len() < 2 - }; - if is_extern_crate_reimport_without_prefix() { - def.vis = vis; - } else { - def.vis = def.vis.min(vis, &self.def_map).unwrap_or(vis); - } + def.vis = def.vis.min(vis, &self.def_map).unwrap_or(vis); } if let Some(def) = defs.values.as_mut() { def.vis = def.vis.min(vis, &self.def_map).unwrap_or(vis); @@ -1648,7 +1642,8 @@ impl DefCollector<'_> { import: Import { ref path, - source: ImportSource { use_tree, id, is_prelude: _, kind: _ }, + source: + ImportSource { use_tree, id, is_prelude: _, kind: _, item_tree_id: _ }, .. }, .. @@ -1730,7 +1725,26 @@ impl ModCollector<'_, '_> { let attrs = self.item_tree.attrs(db, krate, item.into()); if let Some(cfg) = attrs.cfg() { if !self.is_cfg_enabled(&cfg) { - self.emit_unconfigured_diagnostic(self.tree_id, item.into(), &cfg); + let ast_id = match item { + ModItem::Use(it) => self.item_tree[it].ast_id.erase(), + ModItem::ExternCrate(it) => self.item_tree[it].ast_id.erase(), + ModItem::ExternBlock(it) => self.item_tree[it].ast_id.erase(), + ModItem::Function(it) => self.item_tree[it].ast_id.erase(), + ModItem::Struct(it) => self.item_tree[it].ast_id.erase(), + ModItem::Union(it) => self.item_tree[it].ast_id.erase(), + ModItem::Enum(it) => self.item_tree[it].ast_id.erase(), + ModItem::Const(it) => self.item_tree[it].ast_id.erase(), + ModItem::Static(it) => self.item_tree[it].ast_id.erase(), + ModItem::Trait(it) => self.item_tree[it].ast_id.erase(), + ModItem::TraitAlias(it) => self.item_tree[it].ast_id.erase(), + ModItem::Impl(it) => self.item_tree[it].ast_id.erase(), + ModItem::TypeAlias(it) => self.item_tree[it].ast_id.erase(), + ModItem::Mod(it) => self.item_tree[it].ast_id.erase(), + ModItem::MacroCall(it) => self.item_tree[it].ast_id.erase(), + ModItem::MacroRules(it) => self.item_tree[it].ast_id.erase(), + ModItem::Macro2(it) => self.item_tree[it].ast_id.erase(), + }; + self.emit_unconfigured_diagnostic(InFile::new(self.file_id(), ast_id), &cfg); return; } } @@ -1751,7 +1765,7 @@ impl ModCollector<'_, '_> { ModItem::Use(item_tree_id) => { let id = UseLoc { container: module, - id: ItemTreeId::new(self.tree_id, item_tree_id), + id: InFile::new(self.file_id(), self.item_tree[item_tree_id].ast_id), } .intern(db); let is_prelude = attrs.by_key(sym::prelude_import).exists(); @@ -1770,16 +1784,16 @@ impl ModCollector<'_, '_> { ) } ModItem::ExternCrate(item_tree_id) => { + let item_tree::ExternCrate { name, visibility, alias, ast_id } = + &self.item_tree[item_tree_id]; + let id = ExternCrateLoc { container: module, - id: ItemTreeId::new(self.tree_id, item_tree_id), + id: InFile::new(self.tree_id.file_id(), *ast_id), } .intern(db); def_map.modules[self.module_id].scope.define_extern_crate_decl(id); - let item_tree::ExternCrate { name, visibility, alias, ast_id } = - &self.item_tree[item_tree_id]; - let is_self = *name == sym::self_; let resolved = if is_self { cov_mark::hit!(extern_crate_self_as); @@ -1846,7 +1860,7 @@ impl ModCollector<'_, '_> { ModItem::ExternBlock(block) => { let extern_block_id = ExternBlockLoc { container: module, - id: ItemTreeId::new(self.tree_id, block), + id: InFile::new(self.file_id(), self.item_tree[block].ast_id), } .intern(db); self.def_collector.def_map.modules[self.module_id] @@ -1861,15 +1875,20 @@ impl ModCollector<'_, '_> { ModItem::MacroRules(id) => self.collect_macro_rules(id, module), ModItem::Macro2(id) => self.collect_macro_def(id, module), ModItem::Impl(imp) => { - let impl_id = - ImplLoc { container: module, id: ItemTreeId::new(self.tree_id, imp) } - .intern(db); + let impl_id = ImplLoc { + container: module, + id: InFile::new(self.file_id(), self.item_tree[imp].ast_id), + } + .intern(db); self.def_collector.def_map.modules[self.module_id].scope.define_impl(impl_id) } ModItem::Function(id) => { let it = &self.item_tree[id]; - let fn_id = - FunctionLoc { container, id: ItemTreeId::new(self.tree_id, id) }.intern(db); + let fn_id = FunctionLoc { + container, + id: InFile::new(self.tree_id.file_id(), it.ast_id), + } + .intern(db); let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]); @@ -1880,7 +1899,6 @@ impl ModCollector<'_, '_> { if let Some(proc_macro) = attrs.parse_proc_macro_decl(&it.name) { self.def_collector.export_proc_macro( proc_macro, - ItemTreeId::new(self.tree_id, id), InFile::new(self.file_id(), self.item_tree[id].ast_id()), fn_id, ); @@ -1895,7 +1913,7 @@ impl ModCollector<'_, '_> { let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]); update_def( self.def_collector, - StructLoc { container: module, id: ItemTreeId::new(self.tree_id, id) } + StructLoc { container: module, id: InFile::new(self.file_id(), it.ast_id) } .intern(db) .into(), &it.name, @@ -1909,7 +1927,7 @@ impl ModCollector<'_, '_> { let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]); update_def( self.def_collector, - UnionLoc { container: module, id: ItemTreeId::new(self.tree_id, id) } + UnionLoc { container: module, id: InFile::new(self.file_id(), it.ast_id) } .intern(db) .into(), &it.name, @@ -1919,9 +1937,11 @@ impl ModCollector<'_, '_> { } ModItem::Enum(id) => { let it = &self.item_tree[id]; - let enum_ = - EnumLoc { container: module, id: ItemTreeId::new(self.tree_id, id) } - .intern(db); + let enum_ = EnumLoc { + container: module, + id: InFile::new(self.tree_id.file_id(), it.ast_id), + } + .intern(db); let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]); update_def(self.def_collector, enum_.into(), &it.name, vis, false); @@ -1929,7 +1949,8 @@ impl ModCollector<'_, '_> { ModItem::Const(id) => { let it = &self.item_tree[id]; let const_id = - ConstLoc { container, id: ItemTreeId::new(self.tree_id, id) }.intern(db); + ConstLoc { container, id: InFile::new(self.tree_id.file_id(), it.ast_id) } + .intern(db); match &it.name { Some(name) => { @@ -1951,7 +1972,7 @@ impl ModCollector<'_, '_> { let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]); update_def( self.def_collector, - StaticLoc { container, id: ItemTreeId::new(self.tree_id, id) } + StaticLoc { container, id: InFile::new(self.file_id(), it.ast_id) } .intern(db) .into(), &it.name, @@ -1965,7 +1986,7 @@ impl ModCollector<'_, '_> { let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]); update_def( self.def_collector, - TraitLoc { container: module, id: ItemTreeId::new(self.tree_id, id) } + TraitLoc { container: module, id: InFile::new(self.file_id(), it.ast_id) } .intern(db) .into(), &it.name, @@ -1979,9 +2000,12 @@ impl ModCollector<'_, '_> { let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]); update_def( self.def_collector, - TraitAliasLoc { container: module, id: ItemTreeId::new(self.tree_id, id) } - .intern(db) - .into(), + TraitAliasLoc { + container: module, + id: InFile::new(self.file_id(), it.ast_id), + } + .intern(db) + .into(), &it.name, vis, false, @@ -1993,7 +2017,7 @@ impl ModCollector<'_, '_> { let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]); update_def( self.def_collector, - TypeAliasLoc { container, id: ItemTreeId::new(self.tree_id, id) } + TypeAliasLoc { container, id: InFile::new(self.file_id(), it.ast_id) } .intern(db) .into(), &it.name, @@ -2110,8 +2134,10 @@ impl ModCollector<'_, '_> { match is_enabled { Err(cfg) => { self.emit_unconfigured_diagnostic( - self.tree_id, - AttrOwner::ModItem(module_id.into()), + InFile::new( + self.file_id(), + self.item_tree[module_id].ast_id.erase(), + ), &cfg, ); } @@ -2352,7 +2378,7 @@ impl ModCollector<'_, '_> { let macro_id = MacroRulesLoc { container: module, - id: ItemTreeId::new(self.tree_id, id), + id: InFile::new(self.file_id(), mac.ast_id), flags, expander, edition: self.def_collector.def_map.data.edition, @@ -2420,7 +2446,7 @@ impl ModCollector<'_, '_> { let macro_id = Macro2Loc { container: module, - id: ItemTreeId::new(self.tree_id, id), + id: InFile::new(self.file_id(), mac.ast_id), expander, allow_internal_unsafe, edition: self.def_collector.def_map.data.edition, @@ -2565,16 +2591,16 @@ impl ModCollector<'_, '_> { self.def_collector.cfg_options.check(cfg) != Some(false) } - fn emit_unconfigured_diagnostic(&mut self, tree_id: TreeId, item: AttrOwner, cfg: &CfgExpr) { + fn emit_unconfigured_diagnostic(&mut self, ast_id: ErasedAstId, cfg: &CfgExpr) { self.def_collector.def_map.diagnostics.push(DefDiagnostic::unconfigured_code( self.module_id, - tree_id, - item, + ast_id, cfg.clone(), self.def_collector.cfg_options.clone(), )); } + #[inline] fn file_id(&self) -> HirFileId { self.tree_id.file_id() } diff --git a/crates/hir-def/src/nameres/diagnostics.rs b/crates/hir-def/src/nameres/diagnostics.rs index de3d2f48367f..c495a0744919 100644 --- a/crates/hir-def/src/nameres/diagnostics.rs +++ b/crates/hir-def/src/nameres/diagnostics.rs @@ -3,22 +3,18 @@ use std::ops::Not; use cfg::{CfgExpr, CfgOptions}; -use hir_expand::{ExpandErrorKind, MacroCallKind, attrs::AttrId, mod_path::ModPath}; +use hir_expand::{ErasedAstId, ExpandErrorKind, MacroCallKind, attrs::AttrId, mod_path::ModPath}; use la_arena::Idx; use syntax::ast; -use crate::{ - AstId, - item_tree::{self, AttrOwner, ItemTreeId, TreeId}, - nameres::LocalModuleId, -}; +use crate::{AstId, nameres::LocalModuleId}; #[derive(Debug, PartialEq, Eq)] pub enum DefDiagnosticKind { UnresolvedModule { ast: AstId, candidates: Box<[String]> }, UnresolvedExternCrate { ast: AstId }, - UnresolvedImport { id: ItemTreeId, index: Idx }, - UnconfiguredCode { tree: TreeId, item: AttrOwner, cfg: CfgExpr, opts: CfgOptions }, + UnresolvedImport { id: AstId, index: Idx }, + UnconfiguredCode { ast_id: ErasedAstId, cfg: CfgExpr, opts: CfgOptions }, UnresolvedMacroCall { ast: MacroCallKind, path: ModPath }, UnimplementedBuiltinMacro { ast: AstId }, InvalidDeriveTarget { ast: AstId, id: usize }, @@ -28,7 +24,7 @@ pub enum DefDiagnosticKind { } #[derive(Clone, Debug, PartialEq, Eq)] -pub struct DefDiagnostics(Option>>); +pub struct DefDiagnostics(Option>); impl DefDiagnostics { pub fn new(diagnostics: Vec) -> Self { @@ -36,12 +32,12 @@ impl DefDiagnostics { diagnostics .is_empty() .not() - .then(|| triomphe::Arc::new(diagnostics.into_boxed_slice())), + .then(|| triomphe::ThinArc::from_header_and_iter((), diagnostics.into_iter())), ) } pub fn iter(&self) -> impl Iterator { - self.0.as_ref().into_iter().flat_map(|it| &***it) + self.0.as_ref().into_iter().flat_map(|it| &it.slice) } } @@ -75,7 +71,7 @@ impl DefDiagnostic { pub(super) fn unresolved_import( container: LocalModuleId, - id: ItemTreeId, + id: AstId, index: Idx, ) -> Self { Self { in_module: container, kind: DefDiagnosticKind::UnresolvedImport { id, index } } @@ -92,14 +88,13 @@ impl DefDiagnostic { pub fn unconfigured_code( container: LocalModuleId, - tree: TreeId, - item: AttrOwner, + ast_id: ErasedAstId, cfg: CfgExpr, opts: CfgOptions, ) -> Self { Self { in_module: container, - kind: DefDiagnosticKind::UnconfiguredCode { tree, item, cfg, opts }, + kind: DefDiagnosticKind::UnconfiguredCode { ast_id, cfg, opts }, } } diff --git a/crates/hir-def/src/nameres/path_resolution.rs b/crates/hir-def/src/nameres/path_resolution.rs index 74ce33a6419e..e0e32a777356 100644 --- a/crates/hir-def/src/nameres/path_resolution.rs +++ b/crates/hir-def/src/nameres/path_resolution.rs @@ -12,7 +12,6 @@ use either::Either; use hir_expand::{ - Lookup, mod_path::{ModPath, PathKind}, name::Name, }; @@ -529,23 +528,22 @@ impl DefMap { // enum variant cov_mark::hit!(can_import_enum_variant); - let res = - db.enum_variants(e).variants.iter().find(|(_, name)| name == segment).map( - |&(variant, _)| { - let item_tree_id = variant.lookup(db).id; - match item_tree_id.item_tree(db)[item_tree_id.value].shape { - FieldsShape::Record => { - PerNs::types(variant.into(), Visibility::Public, None) - } - FieldsShape::Tuple | FieldsShape::Unit => PerNs::both( - variant.into(), - variant.into(), - Visibility::Public, - None, - ), - } - }, - ); + let res = db + .enum_variants(e) + .variants + .iter() + .find(|(_, name, _)| name == segment) + .map(|&(variant, _, shape)| match shape { + FieldsShape::Record => { + PerNs::types(variant.into(), Visibility::Public, None) + } + FieldsShape::Tuple | FieldsShape::Unit => PerNs::both( + variant.into(), + variant.into(), + Visibility::Public, + None, + ), + }); // FIXME: Need to filter visibility here and below? Not sure. return match res { Some(res) => { diff --git a/crates/hir-def/src/resolver.rs b/crates/hir-def/src/resolver.rs index 16988ddf04b2..491b6204bce2 100644 --- a/crates/hir-def/src/resolver.rs +++ b/crates/hir-def/src/resolver.rs @@ -5,21 +5,22 @@ use base_db::Crate; use hir_expand::{ MacroDefId, mod_path::{ModPath, PathKind}, - name::Name, + name::{AsName, Name}, }; use intern::{Symbol, sym}; use itertools::Itertools as _; use rustc_hash::FxHashSet; use smallvec::{SmallVec, smallvec}; use span::SyntaxContext; +use syntax::ast::HasName; use triomphe::Arc; use crate::{ - AdtId, ConstId, ConstParamId, CrateRootModuleId, DefWithBodyId, EnumId, EnumVariantId, - ExternBlockId, ExternCrateId, FunctionId, FxIndexMap, GenericDefId, GenericParamId, HasModule, - ImplId, ItemContainerId, ItemTreeLoc, LifetimeParamId, LocalModuleId, Lookup, Macro2Id, - MacroId, MacroRulesId, ModuleDefId, ModuleId, ProcMacroId, StaticId, StructId, TraitAliasId, - TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UseId, VariantId, + AdtId, AstIdLoc, ConstId, ConstParamId, CrateRootModuleId, DefWithBodyId, EnumId, + EnumVariantId, ExternBlockId, ExternCrateId, FunctionId, FxIndexMap, GenericDefId, + GenericParamId, HasModule, ImplId, ItemContainerId, LifetimeParamId, LocalModuleId, Lookup, + Macro2Id, MacroId, MacroRulesId, ModuleDefId, ModuleId, ProcMacroId, StaticId, StructId, + TraitAliasId, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UseId, VariantId, builtin_type::BuiltinType, db::DefDatabase, expr_store::{ @@ -32,10 +33,10 @@ use crate::{ generics::{GenericParams, TypeOrConstParamData}, }, item_scope::{BUILTIN_SCOPE, BuiltinShadowMode, ImportOrExternCrate, ImportOrGlob, ItemScope}, - item_tree::ImportAlias, lang_item::LangItemTarget, nameres::{DefMap, LocalDefMap, MacroSubNs, ResolvePathResultPrefixInfo, block_def_map}, per_ns::PerNs, + src::HasSource, type_ref::LifetimeRef, visibility::{RawVisibility, Visibility}, }; @@ -627,14 +628,14 @@ impl<'db> Resolver<'db> { .extern_crate_decls() .filter_map(|id| { let loc = id.lookup(db); - let tree = loc.item_tree_id().item_tree(db); - match &tree[loc.id.value].alias { - Some(alias) => match alias { - ImportAlias::Underscore => None, - ImportAlias::Alias(name) => Some(name.clone()), - }, - None => Some(tree[loc.id.value].name.clone()), - } + let extern_crate = loc.source(db); + // If there is a rename (`as x`), extract the renamed name, or remove the `extern crate` + // if it is an underscore. + extern_crate + .value + .rename() + .map(|a| a.name().map(|it| it.as_name())) + .unwrap_or_else(|| extern_crate.value.name_ref().map(|it| it.as_name())) }) } @@ -1471,10 +1472,7 @@ impl HasResolver for MacroRulesId { fn lookup_resolver( db: &dyn DefDatabase, - lookup: impl Lookup< - Database = dyn DefDatabase, - Data = impl ItemTreeLoc, - >, + lookup: impl Lookup>, ) -> Resolver<'_> { lookup.lookup(db).container().resolver(db) } diff --git a/crates/hir-def/src/signatures.rs b/crates/hir-def/src/signatures.rs index 44cfd72c48f5..b7d29f54d08e 100644 --- a/crates/hir-def/src/signatures.rs +++ b/crates/hir-def/src/signatures.rs @@ -4,21 +4,25 @@ use std::ops::Not as _; use bitflags::bitflags; use cfg::{CfgExpr, CfgOptions}; -use either::Either; -use hir_expand::{InFile, Intern, Lookup, name::Name}; +use hir_expand::{ + InFile, Intern, Lookup, + name::{AsName, Name}, +}; use intern::{Symbol, sym}; use la_arena::{Arena, Idx}; use rustc_abi::{IntegerType, ReprOptions}; use syntax::{ - AstNode, SyntaxNodePtr, - ast::{self, HasGenericParams, IsString}, + NodeOrToken, SyntaxNodePtr, T, + ast::{self, HasGenericParams, HasName, HasVisibility, IsString}, }; use thin_vec::ThinVec; use triomphe::Arc; use crate::{ - ConstId, EnumId, EnumVariantId, EnumVariantLoc, FunctionId, HasModule, ImplId, ItemContainerId, - ModuleId, StaticId, StructId, TraitAliasId, TraitId, TypeAliasId, UnionId, VariantId, + ConstId, EnumId, EnumVariantId, EnumVariantLoc, ExternBlockId, FunctionId, HasModule, ImplId, + ItemContainerId, ModuleId, StaticId, StructId, TraitAliasId, TraitId, TypeAliasId, UnionId, + VariantId, + attr::Attrs, db::DefDatabase, expr_store::{ ExpressionStore, ExpressionStoreSourceMap, @@ -28,15 +32,17 @@ use crate::{ }, }, hir::{ExprId, PatId, generics::GenericParams}, - item_tree::{ - AttrOwner, Field, FieldParent, FieldsShape, FileItemTreeId, ItemTree, ItemTreeId, ModItem, - RawVisibility, RawVisibilityId, - }, + item_tree::{FieldsShape, RawVisibility, visibility_from_ast}, lang_item::LangItem, src::HasSource, type_ref::{TraitRef, TypeBound, TypeRefId}, }; +#[inline] +fn as_name_opt(name: Option) -> Name { + name.map_or_else(Name::missing, |it| it.as_name()) +} + #[derive(Debug, PartialEq, Eq)] pub struct StructSignature { pub name: Name, @@ -70,8 +76,8 @@ bitflags! { impl StructSignature { pub fn query(db: &dyn DefDatabase, id: StructId) -> (Arc, Arc) { let loc = id.lookup(db); - let item_tree = loc.id.item_tree(db); - let attrs = item_tree.attrs(db, loc.container.krate, ModItem::from(loc.id.value).into()); + let InFile { file_id, value: source } = loc.source(db); + let attrs = db.attrs(id.into()); let mut flags = StructFlags::empty(); if attrs.by_key(sym::rustc_has_incoherent_inherent_impls).exists() { @@ -91,23 +97,23 @@ impl StructSignature { } } let repr = attrs.repr(); + let shape = adt_shape(source.kind()); - let hir_expand::files::InFileWrapper { file_id, value } = loc.source(db); let (store, generic_params, source_map) = lower_generic_params( db, loc.container, id.into(), file_id, - value.generic_param_list(), - value.where_clause(), + source.generic_param_list(), + source.where_clause(), ); ( Arc::new(StructSignature { generic_params, store, flags, - shape: item_tree[loc.id.value].shape, - name: item_tree[loc.id.value].name.clone(), + shape, + name: as_name_opt(source.name()), repr, }), Arc::new(source_map), @@ -115,6 +121,15 @@ impl StructSignature { } } +#[inline] +fn adt_shape(adt_kind: ast::StructKind) -> FieldsShape { + match adt_kind { + ast::StructKind::Record(_) => FieldsShape::Record, + ast::StructKind::Tuple(_) => FieldsShape::Tuple, + ast::StructKind::Unit => FieldsShape::Unit, + } +} + #[derive(Debug, PartialEq, Eq)] pub struct UnionSignature { pub name: Name, @@ -127,9 +142,7 @@ pub struct UnionSignature { impl UnionSignature { pub fn query(db: &dyn DefDatabase, id: UnionId) -> (Arc, Arc) { let loc = id.lookup(db); - let krate = loc.container.krate; - let item_tree = loc.id.item_tree(db); - let attrs = item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()); + let attrs = db.attrs(id.into()); let mut flags = StructFlags::empty(); if attrs.by_key(sym::rustc_has_incoherent_inherent_impls).exists() { flags |= StructFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPLS; @@ -140,14 +153,14 @@ impl UnionSignature { let repr = attrs.repr(); - let hir_expand::files::InFileWrapper { file_id, value } = loc.source(db); + let InFile { file_id, value: source } = loc.source(db); let (store, generic_params, source_map) = lower_generic_params( db, loc.container, id.into(), file_id, - value.generic_param_list(), - value.where_clause(), + source.generic_param_list(), + source.where_clause(), ); ( Arc::new(UnionSignature { @@ -155,7 +168,7 @@ impl UnionSignature { store, flags, repr, - name: item_tree[loc.id.value].name.clone(), + name: as_name_opt(source.name()), }), Arc::new(source_map), ) @@ -181,8 +194,7 @@ pub struct EnumSignature { impl EnumSignature { pub fn query(db: &dyn DefDatabase, id: EnumId) -> (Arc, Arc) { let loc = id.lookup(db); - let item_tree = loc.id.item_tree(db); - let attrs = item_tree.attrs(db, loc.container.krate, ModItem::from(loc.id.value).into()); + let attrs = db.attrs(id.into()); let mut flags = EnumFlags::empty(); if attrs.by_key(sym::rustc_has_incoherent_inherent_impls).exists() { flags |= EnumFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPLS; @@ -190,14 +202,14 @@ impl EnumSignature { let repr = attrs.repr(); - let hir_expand::files::InFileWrapper { file_id, value } = loc.source(db); + let InFile { file_id, value: source } = loc.source(db); let (store, generic_params, source_map) = lower_generic_params( db, loc.container, id.into(), file_id, - value.generic_param_list(), - value.where_clause(), + source.generic_param_list(), + source.where_clause(), ); ( @@ -206,7 +218,7 @@ impl EnumSignature { store, flags, repr, - name: item_tree[loc.id.value].name.clone(), + name: as_name_opt(source.name()), }), Arc::new(source_map), ) @@ -239,10 +251,9 @@ pub struct ConstSignature { impl ConstSignature { pub fn query(db: &dyn DefDatabase, id: ConstId) -> (Arc, Arc) { let loc = id.lookup(db); - let item_tree = loc.id.item_tree(db); let module = loc.container.module(db); - let attrs = item_tree.attrs(db, module.krate, ModItem::from(loc.id.value).into()); + let attrs = db.attrs(id.into()); let mut flags = ConstFlags::empty(); if attrs.by_key(sym::rustc_allow_incoherent_impl).exists() { flags |= ConstFlags::RUSTC_ALLOW_INCOHERENT_IMPL; @@ -253,14 +264,14 @@ impl ConstSignature { } let (store, source_map, type_ref) = - crate::expr_store::lower::lower_type_ref(db, module, source.map(|it| it.ty())); + crate::expr_store::lower::lower_type_ref(db, module, source.as_ref().map(|it| it.ty())); ( Arc::new(ConstSignature { store: Arc::new(store), type_ref, flags, - name: item_tree[loc.id.value].name.clone(), + name: source.value.name().map(|it| it.as_name()), }), Arc::new(source_map), ) @@ -295,10 +306,9 @@ pub struct StaticSignature { impl StaticSignature { pub fn query(db: &dyn DefDatabase, id: StaticId) -> (Arc, Arc) { let loc = id.lookup(db); - let item_tree = loc.id.item_tree(db); let module = loc.container.module(db); - let attrs = item_tree.attrs(db, module.krate, ModItem::from(loc.id.value).into()); + let attrs = db.attrs(id.into()); let mut flags = StaticFlags::empty(); if attrs.by_key(sym::rustc_allow_incoherent_impl).exists() { flags |= StaticFlags::RUSTC_ALLOW_INCOHERENT_IMPL; @@ -323,14 +333,14 @@ impl StaticSignature { } let (store, source_map, type_ref) = - crate::expr_store::lower::lower_type_ref(db, module, source.map(|it| it.ty())); + crate::expr_store::lower::lower_type_ref(db, module, source.as_ref().map(|it| it.ty())); ( Arc::new(StaticSignature { store: Arc::new(store), type_ref, flags, - name: item_tree[loc.id.value].name.clone(), + name: as_name_opt(source.value.name()), }), Arc::new(source_map), ) @@ -407,10 +417,9 @@ pub struct TraitSignature { impl TraitSignature { pub fn query(db: &dyn DefDatabase, id: TraitId) -> (Arc, Arc) { let loc = id.lookup(db); - let item_tree = loc.id.item_tree(db); let mut flags = TraitFlags::empty(); - let attrs = item_tree.attrs(db, loc.container.krate, ModItem::from(loc.id.value).into()); + let attrs = db.attrs(id.into()); let source = loc.source(db); if source.value.auto_token().is_some() { flags.insert(TraitFlags::AUTO); @@ -446,15 +455,11 @@ impl TraitSignature { flags |= TraitFlags::SKIP_BOXED_SLICE_DURING_METHOD_DISPATCH; } + let name = as_name_opt(source.value.name()); let (store, source_map, generic_params) = lower_trait(db, loc.container, source, id); ( - Arc::new(TraitSignature { - store: Arc::new(store), - generic_params, - flags, - name: item_tree[loc.id.value].name.clone(), - }), + Arc::new(TraitSignature { store: Arc::new(store), generic_params, flags, name }), Arc::new(source_map), ) } @@ -473,17 +478,13 @@ impl TraitAliasSignature { id: TraitAliasId, ) -> (Arc, Arc) { let loc = id.lookup(db); - let item_tree = loc.id.item_tree(db); let source = loc.source(db); + let name = as_name_opt(source.value.name()); let (store, source_map, generic_params) = lower_trait_alias(db, loc.container, source, id); ( - Arc::new(TraitAliasSignature { - generic_params, - store: Arc::new(store), - name: item_tree[loc.id.value].name.clone(), - }), + Arc::new(TraitAliasSignature { generic_params, store: Arc::new(store), name }), Arc::new(source_map), ) } @@ -530,10 +531,9 @@ impl FunctionSignature { ) -> (Arc, Arc) { let loc = id.lookup(db); let module = loc.container.module(db); - let item_tree = loc.id.item_tree(db); let mut flags = FnFlags::empty(); - let attrs = item_tree.attrs(db, module.krate, ModItem::from(loc.id.value).into()); + let attrs = db.attrs(id.into()); if attrs.by_key(sym::rustc_allow_incoherent_impl).exists() { flags.insert(FnFlags::RUSTC_ALLOW_INCOHERENT_IMPL); } @@ -568,6 +568,7 @@ impl FunctionSignature { flags.insert(FnFlags::HAS_BODY); } + let name = as_name_opt(source.value.name()); let abi = source.value.abi().map(|abi| { abi.abi_string().map_or_else(|| sym::C, |it| Symbol::intern(it.text_without_quotes())) }); @@ -588,7 +589,7 @@ impl FunctionSignature { abi, flags, legacy_const_generics_indices, - name: item_tree[loc.id.value].name.clone(), + name, }), Arc::new(source_map), ) @@ -662,14 +663,9 @@ impl TypeAliasSignature { id: TypeAliasId, ) -> (Arc, Arc) { let loc = id.lookup(db); - let item_tree = loc.id.item_tree(db); let mut flags = TypeAliasFlags::empty(); - let attrs = item_tree.attrs( - db, - loc.container.module(db).krate(), - ModItem::from(loc.id.value).into(), - ); + let attrs = db.attrs(id.into()); if attrs.by_key(sym::rustc_has_incoherent_inherent_impls).exists() { flags.insert(TypeAliasFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPL); } @@ -680,6 +676,7 @@ impl TypeAliasSignature { flags.insert(TypeAliasFlags::IS_EXTERN); } let source = loc.source(db); + let name = as_name_opt(source.value.name()); let (store, source_map, generic_params, bounds, ty) = lower_type_alias(db, loc.container.module(db), source, id); @@ -689,7 +686,7 @@ impl TypeAliasSignature { generic_params, flags, bounds, - name: item_tree[loc.id.value].name.clone(), + name, ty, }), Arc::new(source_map), @@ -743,104 +740,41 @@ impl VariantFields { let (shape, (fields, store, source_map)) = match id { VariantId::EnumVariantId(id) => { let loc = id.lookup(db); - let item_tree = loc.id.item_tree(db); let parent = loc.parent.lookup(db); - let variant = &item_tree[loc.id.value]; - ( - variant.shape, - lower_fields( - db, - parent.container, - &item_tree, - FieldParent::EnumVariant(loc.id.value), - loc.source(db).map(|src| { - variant.fields.iter().zip( - src.field_list() - .map(|it| { - match it { - ast::FieldList::RecordFieldList(record_field_list) => { - Either::Left(record_field_list.fields().map(|it| { - (SyntaxNodePtr::new(it.syntax()), it.ty()) - })) - } - ast::FieldList::TupleFieldList(field_list) => { - Either::Right(field_list.fields().map(|it| { - (SyntaxNodePtr::new(it.syntax()), it.ty()) - })) - } - } - .into_iter() - }) - .into_iter() - .flatten(), - ) - }), - Some(item_tree[parent.id.value].visibility), - ), - ) + let source = loc.source(db); + let shape = adt_shape(source.value.kind()); + let span_map = db.span_map(source.file_id); + let override_visibility = visibility_from_ast( + db, + source.value.parent_enum().visibility(), + &mut |range| span_map.span_for_range(range).ctx, + ); + let fields = lower_field_list( + db, + parent.container, + source.map(|src| src.field_list()), + Some(override_visibility), + ); + (shape, fields) } VariantId::StructId(id) => { let loc = id.lookup(db); - let item_tree = loc.id.item_tree(db); - let strukt = &item_tree[loc.id.value]; - ( - strukt.shape, - lower_fields( - db, - loc.container, - &item_tree, - FieldParent::Struct(loc.id.value), - loc.source(db).map(|src| { - strukt.fields.iter().zip( - src.field_list() - .map(|it| { - match it { - ast::FieldList::RecordFieldList(record_field_list) => { - Either::Left(record_field_list.fields().map(|it| { - (SyntaxNodePtr::new(it.syntax()), it.ty()) - })) - } - ast::FieldList::TupleFieldList(field_list) => { - Either::Right(field_list.fields().map(|it| { - (SyntaxNodePtr::new(it.syntax()), it.ty()) - })) - } - } - .into_iter() - }) - .into_iter() - .flatten(), - ) - }), - None, - ), - ) + let source = loc.source(db); + let shape = adt_shape(source.value.kind()); + let fields = + lower_field_list(db, loc.container, source.map(|src| src.field_list()), None); + (shape, fields) } VariantId::UnionId(id) => { let loc = id.lookup(db); - let item_tree = loc.id.item_tree(db); - let union = &item_tree[loc.id.value]; - ( - FieldsShape::Record, - lower_fields( - db, - loc.container, - &item_tree, - FieldParent::Union(loc.id.value), - loc.source(db).map(|src| { - union.fields.iter().zip( - src.record_field_list() - .map(|it| { - it.fields() - .map(|it| (SyntaxNodePtr::new(it.syntax()), it.ty())) - }) - .into_iter() - .flatten(), - ) - }), - None, - ), - ) + let source = loc.source(db); + let fields = lower_field_list( + db, + loc.container, + source.map(|src| src.record_field_list().map(ast::FieldList::RecordFieldList)), + None, + ); + (FieldsShape::Record, fields) } }; @@ -860,39 +794,81 @@ impl VariantFields { } } -fn lower_fields<'a>( +fn lower_field_list( db: &dyn DefDatabase, module: ModuleId, - item_tree: &ItemTree, - parent: FieldParent, - fields: InFile))>>, - override_visibility: Option, + fields: InFile>, + override_visibility: Option, +) -> (Arena, ExpressionStore, ExpressionStoreSourceMap) { + let file_id = fields.file_id; + match fields.value { + Some(ast::FieldList::RecordFieldList(fields)) => lower_fields( + db, + module, + InFile::new(file_id, fields.fields().map(|field| (field.ty(), field))), + |_, field| as_name_opt(field.name()), + override_visibility, + ), + Some(ast::FieldList::TupleFieldList(fields)) => lower_fields( + db, + module, + InFile::new(file_id, fields.fields().map(|field| (field.ty(), field))), + |idx, _| Name::new_tuple_field(idx), + override_visibility, + ), + None => lower_fields( + db, + module, + InFile::new(file_id, std::iter::empty::<(Option, ast::RecordField)>()), + |_, _| Name::missing(), + None, + ), + } +} + +fn lower_fields( + db: &dyn DefDatabase, + module: ModuleId, + fields: InFile, Field)>>, + mut field_name: impl FnMut(usize, &Field) -> Name, + override_visibility: Option, ) -> (Arena, ExpressionStore, ExpressionStoreSourceMap) { let mut arena = Arena::new(); let cfg_options = module.krate.cfg_options(db); let mut col = ExprCollector::new(db, module, fields.file_id); - for (idx, (field, (ptr, ty))) in fields.value.enumerate() { - let attr_owner = AttrOwner::make_field_indexed(parent, idx); - let attrs = item_tree.attrs(db, module.krate, attr_owner); - if attrs.is_cfg_enabled(cfg_options) { - arena.alloc(FieldData { - name: field.name.clone(), - type_ref: col - .lower_type_ref_opt(ty, &mut ExprCollector::impl_trait_error_allocator), - visibility: item_tree[override_visibility.unwrap_or(field.visibility)].clone(), - is_unsafe: field.is_unsafe, - }); - } else { - col.source_map.diagnostics.push( - crate::expr_store::ExpressionStoreDiagnostics::InactiveCode { - node: InFile::new(fields.file_id, ptr), - cfg: attrs.cfg().unwrap(), - opts: cfg_options.clone(), - }, - ); + let mut idx = 0; + for (ty, field) in fields.value { + match Attrs::is_cfg_enabled_for(db, &field, col.span_map(), cfg_options) { + Ok(()) => { + let type_ref = + col.lower_type_ref_opt(ty, &mut ExprCollector::impl_trait_error_allocator); + let visibility = override_visibility.clone().unwrap_or_else(|| { + visibility_from_ast(db, field.visibility(), &mut |range| { + col.span_map().span_for_range(range).ctx + }) + }); + let is_unsafe = field + .syntax() + .children_with_tokens() + .filter_map(NodeOrToken::into_token) + .any(|token| token.kind() == T![unsafe]); + let name = field_name(idx, &field); + arena.alloc(FieldData { name, type_ref, visibility, is_unsafe }); + idx += 1; + } + Err(cfg) => { + col.source_map.diagnostics.push( + crate::expr_store::ExpressionStoreDiagnostics::InactiveCode { + node: InFile::new(fields.file_id, SyntaxNodePtr::new(field.syntax())), + cfg, + opts: cfg_options.clone(), + }, + ); + } } } let store = col.store.finish(); + arena.shrink_to_fit(); (arena, store, col.source_map) } @@ -905,7 +881,7 @@ pub struct InactiveEnumVariantCode { #[derive(Debug, Clone, PartialEq, Eq)] pub struct EnumVariants { - pub variants: Box<[(EnumVariantId, Name)]>, + pub variants: Box<[(EnumVariantId, Name, FieldsShape)]>, } impl EnumVariants { @@ -914,30 +890,38 @@ impl EnumVariants { e: EnumId, ) -> (Arc, Option>>) { let loc = e.lookup(db); - let item_tree = loc.id.item_tree(db); + let source = loc.source(db); + let ast_id_map = db.ast_id_map(source.file_id); + let span_map = db.span_map(source.file_id); let mut diagnostics = ThinVec::new(); let cfg_options = loc.container.krate.cfg_options(db); let mut index = 0; - let variants = FileItemTreeId::range_iter(item_tree[loc.id.value].variants.clone()) + let Some(variants) = source.value.variant_list() else { + return (Arc::new(EnumVariants { variants: Box::default() }), None); + }; + let variants = variants + .variants() .filter_map(|variant| { - let attrs = item_tree.attrs(db, loc.container.krate, variant.into()); - if attrs.is_cfg_enabled(cfg_options) { - let enum_variant = EnumVariantLoc { - id: ItemTreeId::new(loc.id.tree_id(), variant), - parent: e, - index, + let ast_id = ast_id_map.ast_id(&variant); + match Attrs::is_cfg_enabled_for(db, &variant, span_map.as_ref(), cfg_options) { + Ok(()) => { + let enum_variant = + EnumVariantLoc { id: source.with_value(ast_id), parent: e, index } + .intern(db); + index += 1; + let name = as_name_opt(variant.name()); + let shape = adt_shape(variant.kind()); + Some((enum_variant, name, shape)) + } + Err(cfg) => { + diagnostics.push(InactiveEnumVariantCode { + ast_id, + cfg, + opts: cfg_options.clone(), + }); + None } - .intern(db); - index += 1; - Some((enum_variant, item_tree[variant].name.clone())) - } else { - diagnostics.push(InactiveEnumVariantCode { - ast_id: item_tree[variant].ast_id, - cfg: attrs.cfg().unwrap(), - opts: cfg_options.clone(), - }); - None } }) .collect(); @@ -949,12 +933,18 @@ impl EnumVariants { } pub fn variant(&self, name: &Name) -> Option { - self.variants.iter().find_map(|(v, n)| if n == name { Some(*v) } else { None }) + self.variants.iter().find_map(|(v, n, _)| if n == name { Some(*v) } else { None }) + } + + pub fn variant_name_by_id(&self, variant_id: EnumVariantId) -> Option { + self.variants + .iter() + .find_map(|(id, name, _)| if *id == variant_id { Some(name.clone()) } else { None }) } // [Adopted from rustc](https://github.com/rust-lang/rust/blob/bd53aa3bf7a24a70d763182303bd75e5fc51a9af/compiler/rustc_middle/src/ty/adt.rs#L446-L448) pub fn is_payload_free(&self, db: &dyn DefDatabase) -> bool { - self.variants.iter().all(|&(v, _)| { + self.variants.iter().all(|&(v, _, _)| { // The condition check order is slightly modified from rustc // to improve performance by early returning with relatively fast checks let variant = &db.variant_fields(v.into()); @@ -973,3 +963,17 @@ impl EnumVariants { }) } } + +pub(crate) fn extern_block_abi_query( + db: &dyn DefDatabase, + extern_block: ExternBlockId, +) -> Option { + let source = extern_block.lookup(db).source(db); + source.value.abi().map(|abi| { + match abi.abi_string() { + Some(tok) => Symbol::intern(tok.text_without_quotes()), + // `extern` default to be `extern "C"`. + _ => sym::C, + } + }) +} diff --git a/crates/hir-def/src/src.rs b/crates/hir-def/src/src.rs index 3867f39b8b17..aa373a27b0d5 100644 --- a/crates/hir-def/src/src.rs +++ b/crates/hir-def/src/src.rs @@ -1,15 +1,13 @@ //! Utilities for mapping between hir IDs and the surface syntax. use either::Either; -use hir_expand::InFile; -use la_arena::ArenaMap; +use hir_expand::{AstId, InFile}; +use la_arena::{Arena, ArenaMap, Idx}; use syntax::{AstNode, AstPtr, ast}; use crate::{ - GenericDefId, ItemTreeLoc, LocalFieldId, LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, - UseId, VariantId, - db::DefDatabase, - item_tree::{AttrOwner, FieldParent, ItemTreeNode}, + AstIdLoc, GenericDefId, LocalFieldId, LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, + UseId, VariantId, attr::Attrs, db::DefDatabase, }; pub trait HasSource { @@ -23,18 +21,13 @@ pub trait HasSource { impl HasSource for T where - T: ItemTreeLoc, - T::Id: ItemTreeNode, + T: AstIdLoc, { - type Value = ::Source; + type Value = T::Ast; fn ast_ptr(&self, db: &dyn DefDatabase) -> InFile> { - let id = self.item_tree_id(); - let file_id = id.file_id(); - let tree = id.item_tree(db); - let ast_id_map = db.ast_id_map(file_id); - let node = &tree[id.value]; - - InFile::new(file_id, ast_id_map.get(node.ast_id())) + let id = self.ast_id(); + let ast_id_map = db.ast_id_map(id.file_id); + InFile::new(id.file_id, ast_id_map.get(id.value)) } } @@ -43,18 +36,37 @@ pub trait HasChildSource { fn child_source(&self, db: &dyn DefDatabase) -> InFile>; } +/// Maps a `UseTree` contained in this import back to its AST node. +pub fn use_tree_to_ast( + db: &dyn DefDatabase, + use_ast_id: AstId, + index: Idx, +) -> ast::UseTree { + use_tree_source_map(db, use_ast_id)[index].clone() +} + +/// Maps a `UseTree` contained in this import back to its AST node. +fn use_tree_source_map(db: &dyn DefDatabase, use_ast_id: AstId) -> Arena { + // Re-lower the AST item and get the source map. + // Note: The AST unwraps are fine, since if they fail we should have never obtained `index`. + let ast = use_ast_id.to_node(db); + let ast_use_tree = ast.use_tree().expect("missing `use_tree`"); + let mut span_map = None; + crate::item_tree::lower_use_tree(db, ast_use_tree, &mut |range| { + span_map.get_or_insert_with(|| db.span_map(use_ast_id.file_id)).span_for_range(range).ctx + }) + .expect("failed to lower use tree") + .1 +} + impl HasChildSource> for UseId { type Value = ast::UseTree; fn child_source( &self, db: &dyn DefDatabase, ) -> InFile, Self::Value>> { - let loc = &self.lookup(db); - let use_ = &loc.id.item_tree(db)[loc.id.value]; - InFile::new( - loc.id.file_id(), - use_.use_tree_source_map(db, loc.id.file_id()).into_iter().collect(), - ) + let loc = self.lookup(db); + InFile::new(loc.id.file_id, use_tree_source_map(db, loc.id).into_iter().collect()) } } @@ -124,49 +136,30 @@ impl HasChildSource for VariantId { type Value = Either; fn child_source(&self, db: &dyn DefDatabase) -> InFile> { - let item_tree; - let (src, parent, container) = match *self { + let (src, container) = match *self { VariantId::EnumVariantId(it) => { let lookup = it.lookup(db); - item_tree = lookup.id.item_tree(db); - ( - lookup.source(db).map(|it| it.kind()), - FieldParent::EnumVariant(lookup.id.value), - lookup.parent.lookup(db).container, - ) + (lookup.source(db).map(|it| it.kind()), lookup.parent.lookup(db).container) } VariantId::StructId(it) => { let lookup = it.lookup(db); - item_tree = lookup.id.item_tree(db); - ( - lookup.source(db).map(|it| it.kind()), - FieldParent::Struct(lookup.id.value), - lookup.container, - ) + (lookup.source(db).map(|it| it.kind()), lookup.container) } VariantId::UnionId(it) => { let lookup = it.lookup(db); - item_tree = lookup.id.item_tree(db); - ( - lookup.source(db).map(|it| it.kind()), - FieldParent::Union(lookup.id.value), - lookup.container, - ) + (lookup.source(db).map(|it| it.kind()), lookup.container) } }; - + let span_map = db.span_map(src.file_id); let mut map = ArenaMap::new(); match &src.value { ast::StructKind::Tuple(fl) => { let cfg_options = container.krate.cfg_options(db); let mut idx = 0; - for (i, fd) in fl.fields().enumerate() { - let attrs = item_tree.attrs( - db, - container.krate, - AttrOwner::make_field_indexed(parent, i), - ); - if !attrs.is_cfg_enabled(cfg_options) { + for fd in fl.fields() { + let enabled = + Attrs::is_cfg_enabled_for(db, &fd, span_map.as_ref(), cfg_options).is_ok(); + if !enabled { continue; } map.insert( @@ -179,13 +172,10 @@ impl HasChildSource for VariantId { ast::StructKind::Record(fl) => { let cfg_options = container.krate.cfg_options(db); let mut idx = 0; - for (i, fd) in fl.fields().enumerate() { - let attrs = item_tree.attrs( - db, - container.krate, - AttrOwner::make_field_indexed(parent, i), - ); - if !attrs.is_cfg_enabled(cfg_options) { + for fd in fl.fields() { + let enabled = + Attrs::is_cfg_enabled_for(db, &fd, span_map.as_ref(), cfg_options).is_ok(); + if !enabled { continue; } map.insert( @@ -195,7 +185,7 @@ impl HasChildSource for VariantId { idx += 1; } } - _ => (), + ast::StructKind::Unit => (), } InFile::new(src.file_id, map) } diff --git a/crates/hir-def/src/visibility.rs b/crates/hir-def/src/visibility.rs index 3c67ee9fe5b3..14d67ea804ff 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 e8f6b82434ee..a73a22370d24 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 22b96b55cbb9..710ac6e54223 100644 --- a/crates/hir-ty/src/chalk_db.rs +++ b/crates/hir-ty/src/chalk_db.rs @@ -817,7 +817,7 @@ pub(crate) fn adt_datum_query( .enum_variants(id) .variants .iter() - .map(|&(variant_id, _)| variant_id_to_fields(variant_id.into())) + .map(|&(variant_id, _, _)| variant_id_to_fields(variant_id.into())) .collect(); (rust_ir::AdtKind::Enum, variants) } diff --git a/crates/hir-ty/src/diagnostics/decl_check.rs b/crates/hir-ty/src/diagnostics/decl_check.rs index 099100a73288..fae129fddbfe 100644 --- a/crates/hir-ty/src/diagnostics/decl_check.rs +++ b/crates/hir-ty/src/diagnostics/decl_check.rs @@ -397,7 +397,7 @@ impl<'a> DeclValidator<'a> { fn validate_enum_variants(&mut self, enum_id: EnumId) { let data = self.db.enum_variants(enum_id); - for (variant_id, _) in data.variants.iter() { + for (variant_id, _, _) in data.variants.iter() { self.validate_enum_variant_fields(*variant_id); } @@ -405,7 +405,7 @@ impl<'a> DeclValidator<'a> { let mut enum_variants_replacements = data .variants .iter() - .filter_map(|(_, name)| { + .filter_map(|(_, name, _)| { to_camel_case(&name.display_no_db(edition).to_smolstr()).map(|new_name| { Replacement { current_name: name.clone(), diff --git a/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs b/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs index dd82a0f45ca4..0914b5aac507 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 70763759ef0e..b9b0f9828661 100644 --- a/crates/hir-ty/src/drop.rs +++ b/crates/hir-ty/src/drop.rs @@ -71,7 +71,7 @@ pub(crate) fn has_drop_glue(db: &dyn HirDatabase, ty: Ty, env: Arc { AdtId::EnumId(e) => { let enum_data = self.db.enum_variants(e); - for &(variant, _) in enum_data.variants.iter() { + for &(variant, _, _) in enum_data.variants.iter() { let variant_inhabitedness = self.visit_variant(variant.into(), subst); match variant_inhabitedness { Break(VisiblyUninhabited) => (), diff --git a/crates/hir-ty/src/layout/adt.rs b/crates/hir-ty/src/layout/adt.rs index 3a020bf050d6..a886c33d157b 100644 --- a/crates/hir-ty/src/layout/adt.rs +++ b/crates/hir-ty/src/layout/adt.rs @@ -60,7 +60,7 @@ pub fn layout_of_adt_query( let r = variants .variants .iter() - .map(|&(v, _)| handle_variant(v.into(), &db.variant_fields(v.into()))) + .map(|&(v, _, _)| handle_variant(v.into(), &db.variant_fields(v.into()))) .collect::, _>>()?; (r, db.enum_signature(e).repr.unwrap_or_default(), false) } diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs index 21e5428520e2..8fb8d64779bd 100644 --- a/crates/hir-ty/src/mir/eval.rs +++ b/crates/hir-ty/src/mir/eval.rs @@ -2771,12 +2771,15 @@ impl Evaluator<'_> { Err(e) => { let db = self.db; let loc = variant.lookup(db); - let enum_loc = loc.parent.lookup(db); let edition = self.crate_id.data(self.db).edition; let name = format!( "{}::{}", - enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db, edition), - loc.id.item_tree(db)[loc.id.value].name.display(db, edition), + self.db.enum_signature(loc.parent).name.display(db, edition), + self.db + .enum_variants(loc.parent) + .variant_name_by_id(variant) + .unwrap() + .display(db, edition), ); Err(MirEvalError::ConstEvalError(name, Box::new(e))) } diff --git a/crates/hir-ty/src/mir/eval/shim.rs b/crates/hir-ty/src/mir/eval/shim.rs index 90c52ee96f1f..512a275aa759 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 99d935153037..ef1f215500c2 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 7ae6e907e7ad..91dc2627d184 100644 --- a/crates/hir-ty/src/mir/pretty.rs +++ b/crates/hir-ty/src/mir/pretty.rs @@ -63,16 +63,15 @@ impl MirBody { } hir_def::DefWithBodyId::VariantId(id) => { let loc = id.lookup(db); - let enum_loc = loc.parent.lookup(db); + let edition = this.display_target.edition; w!( this, "enum {}::{} = ", - enum_loc.id.item_tree(db)[enum_loc.id.value] - .name - .display(db, this.display_target.edition), - loc.id.item_tree(db)[loc.id.value] - .name - .display(db, this.display_target.edition), + db.enum_signature(loc.parent).name.display(db, edition), + db.enum_variants(loc.parent) + .variant_name_by_id(id) + .unwrap() + .display(db, edition), ) } }); diff --git a/crates/hir-ty/src/tests.rs b/crates/hir-ty/src/tests.rs index 2b75bd6f1604..48af7b2e32a2 100644 --- a/crates/hir-ty/src/tests.rs +++ b/crates/hir-ty/src/tests.rs @@ -479,7 +479,7 @@ pub(crate) fn visit_module( visit_body(db, &body, cb); } ModuleDefId::AdtId(hir_def::AdtId::EnumId(it)) => { - db.enum_variants(it).variants.iter().for_each(|&(it, _)| { + db.enum_variants(it).variants.iter().for_each(|&(it, _, _)| { let body = db.body(it.into()); cb(it.into()); visit_body(db, &body, cb); diff --git a/crates/hir-ty/src/utils.rs b/crates/hir-ty/src/utils.rs index 1e0ff423ded6..f797e60b05e7 100644 --- a/crates/hir-ty/src/utils.rs +++ b/crates/hir-ty/src/utils.rs @@ -293,9 +293,7 @@ pub fn is_fn_unsafe_to_call( let loc = func.lookup(db); match loc.container { hir_def::ItemContainerId::ExternBlockId(block) => { - let id = block.lookup(db).id; - let is_intrinsic_block = - id.item_tree(db)[id.value].abi.as_ref() == Some(&sym::rust_dash_intrinsic); + let is_intrinsic_block = db.extern_block_abi(block) == Some(sym::rust_dash_intrinsic); if is_intrinsic_block { // legacy intrinsics // extern "rust-intrinsic" intrinsics are unsafe unless they have the rustc_safe_intrinsic attribute diff --git a/crates/hir-ty/src/variance.rs b/crates/hir-ty/src/variance.rs index d6b43aeed4d0..62478d4fd86c 100644 --- a/crates/hir-ty/src/variance.rs +++ b/crates/hir-ty/src/variance.rs @@ -213,7 +213,7 @@ impl Context<'_> { AdtId::StructId(s) => add_constraints_from_variant(VariantId::StructId(s)), AdtId::UnionId(u) => add_constraints_from_variant(VariantId::UnionId(u)), AdtId::EnumId(e) => { - db.enum_variants(e).variants.iter().for_each(|&(variant, _)| { + db.enum_variants(e).variants.iter().for_each(|&(variant, _, _)| { add_constraints_from_variant(VariantId::EnumVariantId(variant)) }); } diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index e8218cf8611f..a88fd14b5bc3 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -52,12 +52,14 @@ use hir_def::{ BindingAnnotation, BindingId, Expr, ExprId, ExprOrPatId, LabelId, Pat, generics::{LifetimeParamData, TypeOrConstParamData, TypeParamProvenance}, }, - item_tree::{AttrOwner, FieldParent, ImportAlias, ItemTreeFieldId, ItemTreeNode}, + item_tree::ImportAlias, layout::{self, ReprOptions, TargetDataLayout}, nameres::{self, diagnostics::DefDiagnostic}, per_ns::PerNs, resolver::{HasResolver, Resolver}, signatures::{ImplFlags, StaticFlags, TraitFlags, VariantFields}, + src::HasSource as _, + visibility::visibility_from_ast, }; use hir_expand::{ AstId, MacroCallKind, RenderedExpandError, ValueResult, attrs::collect_attrs, @@ -81,11 +83,11 @@ use itertools::Itertools; use nameres::diagnostics::DefDiagnosticKind; use rustc_hash::FxHashSet; use smallvec::SmallVec; -use span::{Edition, FileId}; +use span::{AstIdNode, Edition, FileId}; use stdx::{format_to, impl_from, never}; use syntax::{ AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, T, TextRange, ToSmolStr, - ast::{self, HasAttrs as _, HasName}, + ast::{self, HasAttrs as _, HasName, HasVisibility as _}, format_smolstr, }; use triomphe::{Arc, ThinArc}; @@ -687,7 +689,7 @@ impl Module { let source_map = db.enum_signature_with_source_map(e.id).1; expr_store_diagnostics(db, acc, &source_map); let (variants, diagnostics) = db.enum_variants_with_diagnostics(e.id); - let file = e.id.lookup(db).id.file_id(); + let file = e.id.lookup(db).id.file_id; let ast_id_map = db.ast_id_map(file); if let Some(diagnostics) = &diagnostics { for diag in diagnostics.iter() { @@ -704,7 +706,7 @@ impl Module { ); } } - for &(v, _) in &variants.variants { + for &(v, _, _) in &variants.variants { let source_map = db.variant_fields_with_source_map(v.into()).1; push_ty_diagnostics( db, @@ -742,12 +744,10 @@ impl Module { GenericDef::Impl(impl_def).diagnostics(db, acc); let loc = impl_def.id.lookup(db); - let tree = loc.id.item_tree(db); let source_map = db.impl_signature_with_source_map(impl_def.id).1; expr_store_diagnostics(db, acc, &source_map); - let node = &tree[loc.id.value]; - let file_id = loc.id.file_id(); + let file_id = loc.id.file_id; if file_id.macro_file().is_some_and(|it| it.kind(db) == MacroKind::DeriveBuiltIn) { // these expansion come from us, diagnosing them is a waste of resources // FIXME: Once we diagnose the inputs to builtin derives, we should at least extract those diagnostics somehow @@ -765,11 +765,11 @@ impl Module { } if inherent_impls.invalid_impls().contains(&impl_def.id) { - acc.push(IncoherentImpl { impl_: ast_id_map.get(node.ast_id()), file_id }.into()) + acc.push(IncoherentImpl { impl_: ast_id_map.get(loc.id.value), file_id }.into()) } if !impl_def.check_orphan_rules(db) { - acc.push(TraitImplOrphan { impl_: ast_id_map.get(node.ast_id()), file_id }.into()) + acc.push(TraitImplOrphan { impl_: ast_id_map.get(loc.id.value), file_id }.into()) } let trait_ = impl_def.trait_(db); @@ -808,11 +808,11 @@ impl Module { // unsafe negative impl (true, _, true, _) | // unsafe impl for safe trait - (true, false, _, false) => acc.push(TraitImplIncorrectSafety { impl_: ast_id_map.get(node.ast_id()), file_id, should_be_safe: true }.into()), + (true, false, _, false) => acc.push(TraitImplIncorrectSafety { impl_: ast_id_map.get(loc.id.value), file_id, should_be_safe: true }.into()), // safe impl for unsafe trait (false, true, false, _) | // safe impl of dangling drop - (false, false, _, true) => acc.push(TraitImplIncorrectSafety { impl_: ast_id_map.get(node.ast_id()), file_id, should_be_safe: false }.into()), + (false, false, _, true) => acc.push(TraitImplIncorrectSafety { impl_: ast_id_map.get(loc.id.value), file_id, should_be_safe: false }.into()), _ => (), }; @@ -839,7 +839,7 @@ impl Module { TraitImplRedundantAssocItems { trait_, file_id, - impl_: ast_id_map.get(node.ast_id()), + impl_: ast_id_map.get(loc.id.value), assoc_item: (name, assoc_item), } .into(), @@ -857,7 +857,7 @@ impl Module { if !missing.is_empty() { acc.push( TraitImplMissingAssocItems { - impl_: ast_id_map.get(node.ast_id()), + impl_: ast_id_map.get(loc.id.value), file_id, missing, } @@ -1044,73 +1044,25 @@ fn emit_def_diagnostic_( ) } DefDiagnosticKind::UnresolvedImport { id, index } => { - let file_id = id.file_id(); - let item_tree = id.item_tree(db); - let import = &item_tree[id.value]; + let file_id = id.file_id; - let use_tree = import.use_tree_to_ast(db, file_id, *index); + let use_tree = hir_def::src::use_tree_to_ast(db, *id, *index); acc.push( UnresolvedImport { decl: InFile::new(file_id, AstPtr::new(&use_tree)) }.into(), ); } - DefDiagnosticKind::UnconfiguredCode { tree, item, cfg, opts } => { - let item_tree = tree.item_tree(db); - let ast_id_map = db.ast_id_map(tree.file_id()); - // FIXME: This parses... We could probably store relative ranges for the children things - // here in the item tree? - (|| { - let process_field_list = - |field_list: Option<_>, idx: ItemTreeFieldId| match field_list? { - ast::FieldList::RecordFieldList(it) => Some(SyntaxNodePtr::new( - it.fields().nth(idx.into_raw().into_u32() as usize)?.syntax(), - )), - ast::FieldList::TupleFieldList(it) => Some(SyntaxNodePtr::new( - it.fields().nth(idx.into_raw().into_u32() as usize)?.syntax(), - )), - }; - let ptr = match *item { - AttrOwner::ModItem(it) => { - ast_id_map.get(it.ast_id(&item_tree)).syntax_node_ptr() - } - AttrOwner::TopLevel => ast_id_map.root(), - AttrOwner::Variant(it) => { - ast_id_map.get(item_tree[it].ast_id).syntax_node_ptr() - } - AttrOwner::Field(FieldParent::EnumVariant(parent), idx) => process_field_list( - ast_id_map - .get(item_tree[parent].ast_id) - .to_node(&db.parse_or_expand(tree.file_id())) - .field_list(), - idx, - )?, - AttrOwner::Field(FieldParent::Struct(parent), idx) => process_field_list( - ast_id_map - .get(item_tree[parent.index()].ast_id) - .to_node(&db.parse_or_expand(tree.file_id())) - .field_list(), - idx, - )?, - AttrOwner::Field(FieldParent::Union(parent), idx) => SyntaxNodePtr::new( - ast_id_map - .get(item_tree[parent.index()].ast_id) - .to_node(&db.parse_or_expand(tree.file_id())) - .record_field_list()? - .fields() - .nth(idx.into_raw().into_u32() as usize)? - .syntax(), - ), - }; - acc.push( - InactiveCode { - node: InFile::new(tree.file_id(), ptr), - cfg: cfg.clone(), - opts: opts.clone(), - } - .into(), - ); - Some(()) - })(); + DefDiagnosticKind::UnconfiguredCode { ast_id, cfg, opts } => { + let ast_id_map = db.ast_id_map(ast_id.file_id); + let ptr = ast_id_map.get_erased(ast_id.value); + acc.push( + InactiveCode { + node: InFile::new(ast_id.file_id, ptr), + cfg: cfg.clone(), + opts: opts.clone(), + } + .into(), + ); } DefDiagnosticKind::UnresolvedMacroCall { ast, path } => { let (node, precise_location) = precise_macro_call_location(ast, db); @@ -1446,12 +1398,8 @@ impl Struct { impl HasVisibility for Struct { fn visibility(&self, db: &dyn HirDatabase) -> Visibility { let loc = self.id.lookup(db); - let item_tree = loc.id.item_tree(db); - Visibility::resolve( - db, - &self.id.resolver(db), - &item_tree[item_tree[loc.id.value].visibility], - ) + let source = loc.source(db); + visibility_from_ast(db, &self.id.resolver(db), source.map(|src| src.visibility())) } } @@ -1504,12 +1452,8 @@ impl Union { impl HasVisibility for Union { fn visibility(&self, db: &dyn HirDatabase) -> Visibility { let loc = self.id.lookup(db); - let item_tree = loc.id.item_tree(db); - Visibility::resolve( - db, - &self.id.resolver(db), - &item_tree[item_tree[loc.id.value].visibility], - ) + let source = loc.source(db); + visibility_from_ast(db, &self.id.resolver(db), source.map(|src| src.visibility())) } } @@ -1528,7 +1472,7 @@ impl Enum { } pub fn variants(self, db: &dyn HirDatabase) -> Vec { - db.enum_variants(self.id).variants.iter().map(|&(id, _)| Variant { id }).collect() + db.enum_variants(self.id).variants.iter().map(|&(id, _, _)| Variant { id }).collect() } pub fn num_variants(self, db: &dyn HirDatabase) -> usize { @@ -1597,12 +1541,8 @@ impl Enum { impl HasVisibility for Enum { fn visibility(&self, db: &dyn HirDatabase) -> Visibility { let loc = self.id.lookup(db); - let item_tree = loc.id.item_tree(db); - Visibility::resolve( - db, - &self.id.resolver(db), - &item_tree[item_tree[loc.id.value].visibility], - ) + let source = loc.source(db); + visibility_from_ast(db, &self.id.resolver(db), source.map(|src| src.visibility())) } } @@ -2676,10 +2616,9 @@ impl ExternCrateDecl { pub fn resolved_crate(self, db: &dyn HirDatabase) -> Option { let loc = self.id.lookup(db); - let item_tree = loc.id.item_tree(db); let krate = loc.container.krate(); - let name = &item_tree[loc.id.value].name; - if *name == sym::self_ { + let name = self.name(db); + if name == sym::self_ { Some(krate.into()) } else { krate.data(db).dependencies.iter().find_map(|dep| { @@ -2690,25 +2629,29 @@ impl ExternCrateDecl { pub fn name(self, db: &dyn HirDatabase) -> Name { let loc = self.id.lookup(db); - let item_tree = loc.id.item_tree(db); - item_tree[loc.id.value].name.clone() + let source = loc.source(db); + as_name_opt(source.value.name_ref()) } pub fn alias(self, db: &dyn HirDatabase) -> Option { let loc = self.id.lookup(db); - let item_tree = loc.id.item_tree(db); - item_tree[loc.id.value].alias.clone() + let source = loc.source(db); + let rename = source.value.rename()?; + if let Some(name) = rename.name() { + Some(ImportAlias::Alias(name.as_name())) + } else if rename.underscore_token().is_some() { + Some(ImportAlias::Underscore) + } else { + None + } } /// Returns the name under which this crate is made accessible, taking `_` into account. pub fn alias_or_name(self, db: &dyn HirDatabase) -> Option { - let loc = self.id.lookup(db); - let item_tree = loc.id.item_tree(db); - - match &item_tree[loc.id.value].alias { + match self.alias(db) { Some(ImportAlias::Underscore) => None, - Some(ImportAlias::Alias(alias)) => Some(alias.clone()), - None => Some(item_tree[loc.id.value].name.clone()), + Some(ImportAlias::Alias(alias)) => Some(alias), + None => Some(self.name(db)), } } } @@ -2716,12 +2659,8 @@ impl ExternCrateDecl { impl HasVisibility for ExternCrateDecl { fn visibility(&self, db: &dyn HirDatabase) -> Visibility { let loc = self.id.lookup(db); - let item_tree = loc.id.item_tree(db); - Visibility::resolve( - db, - &self.id.resolver(db), - &item_tree[item_tree[loc.id.value].visibility], - ) + let source = loc.source(db); + visibility_from_ast(db, &self.id.resolver(db), source.map(|src| src.visibility())) } } @@ -2841,12 +2780,8 @@ impl Static { impl HasVisibility for Static { fn visibility(&self, db: &dyn HirDatabase) -> Visibility { let loc = self.id.lookup(db); - let item_tree = loc.id.item_tree(db); - Visibility::resolve( - db, - &self.id.resolver(db), - &item_tree[item_tree[loc.id.value].visibility], - ) + let source = loc.source(db); + visibility_from_ast(db, &self.id.resolver(db), source.map(|src| src.visibility())) } } @@ -2935,11 +2870,7 @@ impl Trait { } fn all_macro_calls(&self, db: &dyn HirDatabase) -> Box<[(AstId, MacroCallId)]> { - db.trait_items(self.id) - .macro_calls - .as_ref() - .map(|it| it.as_ref().clone().into_boxed_slice()) - .unwrap_or_default() + db.trait_items(self.id).macro_calls.to_vec().into_boxed_slice() } /// `#[rust_analyzer::completions(...)]` mode. @@ -2951,12 +2882,8 @@ impl Trait { impl HasVisibility for Trait { fn visibility(&self, db: &dyn HirDatabase) -> Visibility { let loc = self.id.lookup(db); - let item_tree = loc.id.item_tree(db); - Visibility::resolve( - db, - &self.id.resolver(db), - &item_tree[item_tree[loc.id.value].visibility], - ) + let source = loc.source(db); + visibility_from_ast(db, &self.id.resolver(db), source.map(|src| src.visibility())) } } @@ -2978,12 +2905,8 @@ impl TraitAlias { impl HasVisibility for TraitAlias { fn visibility(&self, db: &dyn HirDatabase) -> Visibility { let loc = self.id.lookup(db); - let item_tree = loc.id.item_tree(db); - Visibility::resolve( - db, - &self.id.resolver(db), - &item_tree[item_tree[loc.id.value].visibility], - ) + let source = loc.source(db); + visibility_from_ast(db, &self.id.resolver(db), source.map(|src| src.visibility())) } } @@ -3131,25 +3054,23 @@ impl Macro { match self.id { MacroId::Macro2Id(id) => { let loc = id.lookup(db); - let item_tree = loc.id.item_tree(db); - item_tree[loc.id.value].name.clone() + let source = loc.source(db); + as_name_opt(source.value.name()) } MacroId::MacroRulesId(id) => { let loc = id.lookup(db); - let item_tree = loc.id.item_tree(db); - item_tree[loc.id.value].name.clone() + let source = loc.source(db); + as_name_opt(source.value.name()) } MacroId::ProcMacroId(id) => { let loc = id.lookup(db); - let item_tree = loc.id.item_tree(db); + let source = loc.source(db); match loc.kind { ProcMacroKind::CustomDerive => db .attrs(id.into()) .parse_proc_macro_derive() - .map_or_else(|| item_tree[loc.id.value].name.clone(), |(it, _)| it), - ProcMacroKind::Bang | ProcMacroKind::Attr => { - item_tree[loc.id.value].name.clone() - } + .map_or_else(|| as_name_opt(source.value.name()), |(it, _)| it), + ProcMacroKind::Bang | ProcMacroKind::Attr => as_name_opt(source.value.name()), } } } @@ -3246,12 +3167,8 @@ impl HasVisibility for Macro { match self.id { MacroId::Macro2Id(id) => { let loc = id.lookup(db); - let item_tree = loc.id.item_tree(db); - Visibility::resolve( - db, - &id.resolver(db), - &item_tree[item_tree[loc.id.value].visibility], - ) + let source = loc.source(db); + visibility_from_ast(db, &id.resolver(db), source.map(|src| src.visibility())) } MacroId::MacroRulesId(_) => Visibility::Public, MacroId::ProcMacroId(_) => Visibility::Public, @@ -3405,7 +3322,7 @@ fn as_assoc_item<'db, ID, DEF, LOC>( where ID: Lookup>, DEF: From, - LOC: ItemTreeNode, + LOC: AstIdNode, { match id.lookup(db).container { ItemContainerId::TraitId(_) | ItemContainerId::ImplId(_) => Some(ctor(DEF::from(id))), @@ -3421,7 +3338,7 @@ fn as_extern_assoc_item<'db, ID, DEF, LOC>( where ID: Lookup>, DEF: From, - LOC: ItemTreeNode, + LOC: AstIdNode, { match id.lookup(db).container { ItemContainerId::ExternBlockId(_) => Some(ctor(DEF::from(id))), @@ -4513,11 +4430,7 @@ impl Impl { } fn all_macro_calls(&self, db: &dyn HirDatabase) -> Box<[(AstId, MacroCallId)]> { - db.impl_items(self.id) - .macro_calls - .as_ref() - .map(|it| it.as_ref().clone().into_boxed_slice()) - .unwrap_or_default() + db.impl_items(self.id).macro_calls.to_vec().into_boxed_slice() } } @@ -6478,3 +6391,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 a150df70502b..dbf9cf8a1de9 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); } } @@ -197,16 +197,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.expansions().filter(|(ast, _)| ast.file_id == file_id).for_each( @@ -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 630dd7101d4be6c925258baa7aad588292f645fd Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Wed, 21 May 2025 13:42:48 +0300 Subject: [PATCH 3/6] 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 65dc35337a52..07d1500fc097 100644 --- a/crates/hir-def/src/item_tree.rs +++ b/crates/hir-def/src/item_tree.rs @@ -29,7 +29,6 @@ //! //! In general, any item in the `ItemTree` stores its `AstId`, which allows mapping it back to its //! surface syntax. -#![allow(unexpected_cfgs)] mod lower; mod pretty; @@ -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 57765427693d..d9588cb487d6 100644 --- a/crates/hir-def/src/item_tree/lower.rs +++ b/crates/hir-def/src/item_tree/lower.rs @@ -8,23 +8,22 @@ use hir_expand::{ name::AsName, span_map::{SpanMap, SpanMapRef}, }; -use intern::{Symbol, sym}; use la_arena::Arena; use span::{AstIdMap, SyntaxContext}; use syntax::{ AstNode, - ast::{self, HasModuleItem, HasName, IsString}, + ast::{self, HasModuleItem, HasName}, }; use triomphe::Arc; use crate::{ db::DefDatabase, item_tree::{ - AssocItem, AttrOwner, Const, Enum, ExternBlock, ExternCrate, Field, FieldParent, - FieldsShape, FileItemTreeId, Function, Idx, Impl, ImportAlias, Interned, ItemTree, - ItemTreeData, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, ModPath, Name, Range, - RawAttrs, RawIdx, RawVisibility, RawVisibilityId, Static, Struct, StructKind, Trait, - TraitAlias, TypeAlias, Union, Use, UseTree, UseTreeKind, Variant, VisibilityExplicitness, + AttrOwner, Const, Enum, ExternBlock, ExternCrate, FieldsShape, FileItemTreeId, Function, + Idx, Impl, ImportAlias, Interned, ItemTree, ItemTreeData, Macro2, MacroCall, MacroRules, + Mod, ModItem, ModKind, ModPath, RawAttrs, RawVisibility, RawVisibilityId, Static, Struct, + StructKind, Trait, TraitAlias, TypeAlias, Union, Use, UseTree, UseTreeKind, + VisibilityExplicitness, }, }; @@ -163,118 +162,23 @@ impl<'a> Ctx<'a> { } } - fn lower_assoc_item(&mut self, item_node: &ast::AssocItem) -> Option { - let item: AssocItem = match item_node { - ast::AssocItem::Fn(ast) => self.lower_function(ast).map(Into::into), - ast::AssocItem::TypeAlias(ast) => self.lower_type_alias(ast).map(Into::into), - ast::AssocItem::Const(ast) => Some(self.lower_const(ast).into()), - ast::AssocItem::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into), - }?; - let attrs = RawAttrs::new(self.db, item_node, self.span_map()); - self.add_attrs( - match item { - AssocItem::Function(it) => AttrOwner::ModItem(ModItem::Function(it)), - AssocItem::TypeAlias(it) => AttrOwner::ModItem(ModItem::TypeAlias(it)), - AssocItem::Const(it) => AttrOwner::ModItem(ModItem::Const(it)), - AssocItem::MacroCall(it) => AttrOwner::ModItem(ModItem::MacroCall(it)), - }, - attrs, - ); - Some(item) - } - fn lower_struct(&mut self, strukt: &ast::Struct) -> Option> { let visibility = self.lower_visibility(strukt); let name = strukt.name()?.as_name(); let ast_id = self.source_ast_id_map.ast_id(strukt); - let (fields, kind, attrs) = self.lower_fields(&strukt.kind()); - let res = Struct { name, visibility, fields, shape: kind, ast_id }; + let shape = adt_shape(strukt.kind()); + let res = Struct { name, visibility, shape, ast_id }; let id = id(self.data().structs.alloc(res)); - for (idx, attr) in attrs { - self.add_attrs( - AttrOwner::Field( - FieldParent::Struct(id), - Idx::from_raw(RawIdx::from_u32(idx as u32)), - ), - attr, - ); - } Some(id) } - fn lower_fields( - &mut self, - strukt_kind: &ast::StructKind, - ) -> (Box<[Field]>, FieldsShape, Vec<(usize, RawAttrs)>) { - match strukt_kind { - ast::StructKind::Record(it) => { - let mut fields = vec![]; - let mut attrs = vec![]; - - for (i, field) in it.fields().enumerate() { - let data = self.lower_record_field(&field); - fields.push(data); - let attr = RawAttrs::new(self.db, &field, self.span_map()); - if !attr.is_empty() { - attrs.push((i, attr)) - } - } - (fields.into(), FieldsShape::Record, attrs) - } - ast::StructKind::Tuple(it) => { - let mut fields = vec![]; - let mut attrs = vec![]; - - for (i, field) in it.fields().enumerate() { - let data = self.lower_tuple_field(i, &field); - fields.push(data); - let attr = RawAttrs::new(self.db, &field, self.span_map()); - if !attr.is_empty() { - attrs.push((i, attr)) - } - } - (fields.into(), FieldsShape::Tuple, attrs) - } - ast::StructKind::Unit => (Box::default(), FieldsShape::Unit, Vec::default()), - } - } - - fn lower_record_field(&mut self, field: &ast::RecordField) -> Field { - let name = match field.name() { - Some(name) => name.as_name(), - None => Name::missing(), - }; - let visibility = self.lower_visibility(field); - - Field { name, visibility, is_unsafe: field.unsafe_token().is_some() } - } - - fn lower_tuple_field(&mut self, idx: usize, field: &ast::TupleField) -> Field { - let name = Name::new_tuple_field(idx); - let visibility = self.lower_visibility(field); - Field { name, visibility, is_unsafe: false } - } - fn lower_union(&mut self, union: &ast::Union) -> Option> { let visibility = self.lower_visibility(union); let name = union.name()?.as_name(); let ast_id = self.source_ast_id_map.ast_id(union); - let (fields, _, attrs) = match union.record_field_list() { - Some(record_field_list) => self.lower_fields(&StructKind::Record(record_field_list)), - None => (Box::default(), FieldsShape::Record, Vec::default()), - }; - let res = Union { name, visibility, fields, ast_id }; + let res = Union { name, visibility, ast_id }; let id = id(self.data().unions.alloc(res)); - for (idx, attr) in attrs { - self.add_attrs( - AttrOwner::Field( - FieldParent::Union(id), - Idx::from_raw(RawIdx::from_u32(idx as u32)), - ), - attr, - ); - } Some(id) } @@ -282,48 +186,11 @@ impl<'a> Ctx<'a> { let visibility = self.lower_visibility(enum_); let name = enum_.name()?.as_name(); let ast_id = self.source_ast_id_map.ast_id(enum_); - let variants = match &enum_.variant_list() { - Some(variant_list) => self.lower_variants(variant_list), - None => { - FileItemTreeId(self.next_variant_idx())..FileItemTreeId(self.next_variant_idx()) - } - }; - let res = Enum { name, visibility, variants, ast_id }; + let res = Enum { name, visibility, ast_id }; let id = id(self.data().enums.alloc(res)); Some(id) } - fn lower_variants(&mut self, variants: &ast::VariantList) -> Range> { - let start = self.next_variant_idx(); - for variant in variants.variants() { - let idx = self.lower_variant(&variant); - self.add_attrs(id(idx).into(), RawAttrs::new(self.db, &variant, self.span_map())); - } - let end = self.next_variant_idx(); - FileItemTreeId(start)..FileItemTreeId(end) - } - - fn lower_variant(&mut self, variant: &ast::Variant) -> Idx { - let name = match variant.name() { - Some(name) => name.as_name(), - None => Name::missing(), - }; - let (fields, kind, attrs) = self.lower_fields(&variant.kind()); - let ast_id = self.source_ast_id_map.ast_id(variant); - let res = Variant { name, fields, shape: kind, ast_id }; - let id = self.data().variants.alloc(res); - for (idx, attr) in attrs { - self.add_attrs( - AttrOwner::Field( - FieldParent::EnumVariant(FileItemTreeId(id)), - Idx::from_raw(RawIdx::from_u32(idx as u32)), - ), - attr, - ); - } - id - } - fn lower_function(&mut self, func: &ast::Fn) -> Option> { let visibility = self.lower_visibility(func); let name = func.name()?.as_name(); @@ -390,14 +257,7 @@ impl<'a> Ctx<'a> { let visibility = self.lower_visibility(trait_def); let ast_id = self.source_ast_id_map.ast_id(trait_def); - let items = trait_def - .assoc_item_list() - .into_iter() - .flat_map(|list| list.assoc_items()) - .filter_map(|item_node| self.lower_assoc_item(&item_node)) - .collect(); - - let def = Trait { name, visibility, items, ast_id }; + let def = Trait { name, visibility, ast_id }; let id = id(self.data().traits.alloc(def)); Some(id) } @@ -417,16 +277,9 @@ impl<'a> Ctx<'a> { fn lower_impl(&mut self, impl_def: &ast::Impl) -> FileItemTreeId { let ast_id = self.source_ast_id_map.ast_id(impl_def); - // We cannot use `assoc_items()` here as that does not include macro calls. - let items = impl_def - .assoc_item_list() - .into_iter() - .flat_map(|it| it.assoc_items()) - .filter_map(|item| self.lower_assoc_item(&item)) - .collect(); // Note that trait impls don't get implicit `Self` unlike traits, because here they are a // type alias rather than a type parameter, so this is handled by the resolver. - let res = Impl { items, ast_id }; + let res = Impl { ast_id }; id(self.data().impls.alloc(res)) } @@ -489,7 +342,6 @@ impl<'a> Ctx<'a> { fn lower_extern_block(&mut self, block: &ast::ExternBlock) -> FileItemTreeId { let ast_id = self.source_ast_id_map.ast_id(block); - let abi = block.abi().map(lower_abi); let children: Box<[_]> = block.extern_item_list().map_or(Box::new([]), |list| { list.extern_items() .filter_map(|item| { @@ -510,7 +362,7 @@ impl<'a> Ctx<'a> { .collect() }); - let res = ExternBlock { abi, ast_id, children }; + let res = ExternBlock { ast_id, children }; id(self.data().extern_blocks.alloc(res)) } @@ -520,20 +372,6 @@ impl<'a> Ctx<'a> { }); self.data().vis.alloc(vis) } - - fn next_variant_idx(&self) -> Idx { - Idx::from_raw(RawIdx::from( - self.tree.data.as_ref().map_or(0, |data| data.variants.len() as u32), - )) - } -} - -fn lower_abi(abi: ast::Abi) -> Symbol { - match abi.abi_string() { - Some(tok) => Symbol::intern(tok.text_without_quotes()), - // `extern` default to be `extern "C"`. - _ => sym::C, - } } struct UseTreeLowering<'a> { @@ -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 8ff14751c671..0c62b86dae28 100644 --- a/crates/hir-def/src/item_tree/pretty.rs +++ b/crates/hir-def/src/item_tree/pretty.rs @@ -2,15 +2,13 @@ use std::fmt::{self, Write}; -use la_arena::{Idx, RawIdx}; use span::{Edition, ErasedFileAstId}; use crate::{ item_tree::{ - AttrOwner, Const, DefDatabase, Enum, ExternBlock, ExternCrate, Field, FieldParent, - FieldsShape, FileItemTreeId, Function, Impl, ItemTree, Macro2, MacroCall, MacroRules, Mod, - ModItem, ModKind, RawAttrs, RawVisibilityId, Static, Struct, Trait, TraitAlias, TypeAlias, - Union, Use, UseTree, UseTreeKind, Variant, + AttrOwner, Const, DefDatabase, Enum, ExternBlock, ExternCrate, FieldsShape, Function, Impl, + ItemTree, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, RawAttrs, RawVisibilityId, + Static, Struct, Trait, TraitAlias, TypeAlias, Union, Use, UseTree, UseTreeKind, }, visibility::RawVisibility, }; @@ -118,44 +116,14 @@ impl Printer<'_> { }; } - fn print_fields(&mut self, parent: FieldParent, kind: FieldsShape, fields: &[Field]) { - let edition = self.edition; + fn print_fields(&mut self, kind: FieldsShape) { match kind { FieldsShape::Record => { self.whitespace(); - w!(self, "{{"); - self.indented(|this| { - for (idx, Field { name, visibility, is_unsafe }) in fields.iter().enumerate() { - this.print_attrs_of( - AttrOwner::Field(parent, Idx::from_raw(RawIdx::from(idx as u32))), - "\n", - ); - this.print_visibility(*visibility); - if *is_unsafe { - w!(this, "unsafe "); - } - - wln!(this, "{},", name.display(self.db, edition)); - } - }); - w!(self, "}}"); + w!(self, "{{ ... }}"); } FieldsShape::Tuple => { - w!(self, "("); - self.indented(|this| { - for (idx, Field { name, visibility, is_unsafe }) in fields.iter().enumerate() { - this.print_attrs_of( - AttrOwner::Field(parent, Idx::from_raw(RawIdx::from(idx as u32))), - "\n", - ); - this.print_visibility(*visibility); - if *is_unsafe { - w!(this, "unsafe "); - } - wln!(this, "{},", name.display(self.db, edition)); - } - }); - w!(self, ")"); + w!(self, "(...)"); } FieldsShape::Unit => {} } @@ -214,13 +182,9 @@ impl Printer<'_> { wln!(self, ";"); } ModItem::ExternBlock(it) => { - let ExternBlock { abi, ast_id, children } = &self.tree[it]; + let ExternBlock { ast_id, children } = &self.tree[it]; self.print_ast_id(ast_id.erase()); - w!(self, "extern "); - if let Some(abi) = abi { - w!(self, "\"{}\" ", abi); - } - w!(self, "{{"); + w!(self, "extern {{"); self.indented(|this| { for child in &**children { this.print_mod_item(*child); @@ -235,11 +199,11 @@ impl Printer<'_> { wln!(self, "fn {};", name.display(self.db, self.edition)); } ModItem::Struct(it) => { - let Struct { visibility, name, fields, shape: kind, ast_id } = &self.tree[it]; + let Struct { visibility, name, shape: kind, ast_id } = &self.tree[it]; self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); w!(self, "struct {}", name.display(self.db, self.edition)); - self.print_fields(FieldParent::Struct(it), *kind, fields); + self.print_fields(*kind); if matches!(kind, FieldsShape::Record) { wln!(self); } else { @@ -247,30 +211,18 @@ impl Printer<'_> { } } ModItem::Union(it) => { - let Union { name, visibility, fields, ast_id } = &self.tree[it]; + let Union { name, visibility, ast_id } = &self.tree[it]; self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); w!(self, "union {}", name.display(self.db, self.edition)); - self.print_fields(FieldParent::Union(it), FieldsShape::Record, fields); + self.print_fields(FieldsShape::Record); wln!(self); } ModItem::Enum(it) => { - let Enum { name, visibility, variants, ast_id } = &self.tree[it]; + let Enum { name, visibility, ast_id } = &self.tree[it]; self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); - w!(self, "enum {} {{", name.display(self.db, self.edition)); - let edition = self.edition; - self.indented(|this| { - for variant in FileItemTreeId::range_iter(variants.clone()) { - let Variant { name, fields, shape: kind, ast_id } = &this.tree[variant]; - this.print_ast_id(ast_id.erase()); - this.print_attrs_of(variant, "\n"); - w!(this, "{}", name.display(self.db, edition)); - this.print_fields(FieldParent::EnumVariant(variant), *kind, fields); - wln!(this, ","); - } - }); - wln!(self, "}}"); + w!(self, "enum {} {{ ... }}", name.display(self.db, self.edition)); } ModItem::Const(it) => { let Const { name, visibility, ast_id } = &self.tree[it]; @@ -293,16 +245,10 @@ impl Printer<'_> { wln!(self); } ModItem::Trait(it) => { - let Trait { name, visibility, items, ast_id } = &self.tree[it]; + let Trait { name, visibility, ast_id } = &self.tree[it]; self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); - w!(self, "trait {} {{", name.display(self.db, self.edition)); - self.indented(|this| { - for item in &**items { - this.print_mod_item((*item).into()); - } - }); - wln!(self, "}}"); + w!(self, "trait {} {{ ... }}", name.display(self.db, self.edition)); } ModItem::TraitAlias(it) => { let TraitAlias { name, visibility, ast_id } = &self.tree[it]; @@ -311,15 +257,9 @@ impl Printer<'_> { wln!(self, "trait {} = ..;", name.display(self.db, self.edition)); } ModItem::Impl(it) => { - let Impl { items, ast_id } = &self.tree[it]; + let Impl { ast_id } = &self.tree[it]; self.print_ast_id(ast_id.erase()); - w!(self, "impl {{"); - self.indented(|this| { - for item in &**items { - this.print_mod_item((*item).into()); - } - }); - wln!(self, "}}"); + w!(self, "impl {{ ... }}"); } ModItem::TypeAlias(it) => { let TypeAlias { name, visibility, ast_id } = &self.tree[it]; diff --git a/crates/hir-def/src/item_tree/tests.rs b/crates/hir-def/src/item_tree/tests.rs index 7a85e8d175e6..e39efd31c6c1 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 56c750c6254d56e57db1c39e0745e024a1fcfd1e Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Wed, 21 May 2025 14:59:21 +0300 Subject: [PATCH 4/6] Ignore ast id hashes in typos check --- .typos.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/.typos.toml b/.typos.toml index e938bddd4b12..cdbc003a8088 100644 --- a/.typos.toml +++ b/.typos.toml @@ -18,6 +18,7 @@ extend-ignore-re = [ "INOUT", "optin", "=Pn", + "\\[[0-9A-F]{4},", # AstId hex hashes # ignore `// spellchecker:off` until `// spellchecker:on` "(?s)(#|//)\\s*spellchecker:off.*?\\n\\s*(#|//)\\s*spellchecker:on", ] From f4b700ea5e9891aff4984c1f814af4e7a4f26b31 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Wed, 21 May 2025 15:24:07 +0300 Subject: [PATCH 5/6] 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 7cb1b6c02075..b7df3ee2f911 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 b35f140ae2a191ec787f0399488d007ee2c35727 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Fri, 6 Jun 2025 15:09:55 +0300 Subject: [PATCH 6/6] Fix new incremental benchmarks This benchmarks don't measure what they were supposed to, but that's a matter for another time. The reason we *add* a query to the list is because previously the attrs in the signature queries were computed directly from the item tree and now they call `db.attrs()`. The reason we don't *remove* any query is because, as I said, those benchmarks don't measure what they should --- crates/hir-ty/src/tests/incremental.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/hir-ty/src/tests/incremental.rs b/crates/hir-ty/src/tests/incremental.rs index e8e3812c69d3..f197e86d9df6 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(), ];