Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-expand/src/db.rs')
-rw-r--r--crates/hir-expand/src/db.rs278
1 files changed, 27 insertions, 251 deletions
diff --git a/crates/hir-expand/src/db.rs b/crates/hir-expand/src/db.rs
index 2f8c0951b1..8c43017971 100644
--- a/crates/hir-expand/src/db.rs
+++ b/crates/hir-expand/src/db.rs
@@ -1,16 +1,11 @@
//! Defines database & queries for macro expansion.
-use std::sync::OnceLock;
-
-use base_db::{
- salsa::{self, debug::DebugQueryTable},
- CrateId, Edition, FileId, SourceDatabase, VersionReq,
-};
+use base_db::{salsa, CrateId, FileId, SourceDatabase};
use either::Either;
use limit::Limit;
use mbe::{syntax_node_to_token_tree, ValueResult};
use rustc_hash::FxHashSet;
-use span::{Span, SyntaxContextId};
+use span::SyntaxContextId;
use syntax::{
ast::{self, HasAttrs},
AstNode, Parse, SyntaxError, SyntaxNode, SyntaxToken, T,
@@ -19,13 +14,14 @@ use triomphe::Arc;
use crate::{
ast_id_map::AstIdMap,
- attrs::{collect_attrs, RawAttrs},
+ attrs::collect_attrs,
builtin_attr_macro::pseudo_derive_attr_expansion,
builtin_fn_macro::EagerExpander,
+ declarative::DeclarativeMacroExpander,
fixup::{self, reverse_fixups, SyntaxFixupUndoInfo},
hygiene::{
- apply_mark, span_with_call_site_ctxt, span_with_def_site_ctxt, span_with_mixed_site_ctxt,
- SyntaxContextData, Transparency,
+ span_with_call_site_ctxt, span_with_def_site_ctxt, span_with_mixed_site_ctxt,
+ SyntaxContextData,
},
proc_macro::ProcMacros,
span_map::{RealSpanMap, SpanMap, SpanMapRef},
@@ -44,82 +40,6 @@ use crate::{
static TOKEN_LIMIT: Limit = Limit::new(1_048_576);
#[derive(Debug, Clone, Eq, PartialEq)]
-/// Old-style `macro_rules` or the new macros 2.0
-pub struct DeclarativeMacroExpander {
- pub mac: mbe::DeclarativeMacro<span::Span>,
- pub transparency: Transparency,
-}
-
-// FIXME: Remove this once we drop support for 1.76
-static REQUIREMENT: OnceLock<VersionReq> = OnceLock::new();
-
-impl DeclarativeMacroExpander {
- pub fn expand(
- &self,
- db: &dyn ExpandDatabase,
- tt: tt::Subtree,
- call_id: MacroCallId,
- ) -> ExpandResult<tt::Subtree> {
- let loc = db.lookup_intern_macro_call(call_id);
- let toolchain = &db.crate_graph()[loc.def.krate].toolchain;
- let new_meta_vars = toolchain.as_ref().map_or(false, |version| {
- REQUIREMENT.get_or_init(|| VersionReq::parse(">=1.76").unwrap()).matches(
- &base_db::Version {
- pre: base_db::Prerelease::EMPTY,
- build: base_db::BuildMetadata::EMPTY,
- major: version.major,
- minor: version.minor,
- patch: version.patch,
- },
- )
- });
- match self.mac.err() {
- Some(e) => ExpandResult::new(
- tt::Subtree::empty(tt::DelimSpan { open: loc.call_site, close: loc.call_site }),
- ExpandError::other(format!("invalid macro definition: {e}")),
- ),
- None => self
- .mac
- .expand(
- &tt,
- |s| s.ctx = apply_mark(db, s.ctx, call_id, self.transparency),
- new_meta_vars,
- loc.call_site,
- )
- .map_err(Into::into),
- }
- }
-
- pub fn expand_unhygienic(
- &self,
- db: &dyn ExpandDatabase,
- tt: tt::Subtree,
- krate: CrateId,
- call_site: Span,
- ) -> ExpandResult<tt::Subtree> {
- let toolchain = &db.crate_graph()[krate].toolchain;
- let new_meta_vars = toolchain.as_ref().map_or(false, |version| {
- REQUIREMENT.get_or_init(|| VersionReq::parse(">=1.76").unwrap()).matches(
- &base_db::Version {
- pre: base_db::Prerelease::EMPTY,
- build: base_db::BuildMetadata::EMPTY,
- major: version.major,
- minor: version.minor,
- patch: version.patch,
- },
- )
- });
- match self.mac.err() {
- Some(e) => ExpandResult::new(
- tt::Subtree::empty(tt::DelimSpan { open: call_site, close: call_site }),
- ExpandError::other(format!("invalid macro definition: {e}")),
- ),
- None => self.mac.expand(&tt, |_| (), new_meta_vars, call_site).map_err(Into::into),
- }
- }
-}
-
-#[derive(Debug, Clone, Eq, PartialEq)]
pub enum TokenExpander {
/// Old-style `macro_rules` or the new macros 2.0
DeclarativeMacro(Arc<DeclarativeMacroExpander>),
@@ -141,6 +61,7 @@ pub trait ExpandDatabase: SourceDatabase {
#[salsa::input]
fn proc_macros(&self) -> Arc<ProcMacros>;
+ #[salsa::invoke(AstIdMap::ast_id_map)]
fn ast_id_map(&self, file_id: HirFileId) -> Arc<AstIdMap>;
/// Main public API -- parses a hir file, not caring whether it's a real
@@ -156,8 +77,10 @@ pub trait ExpandDatabase: SourceDatabase {
macro_file: MacroFileId,
) -> ExpandResult<(Parse<SyntaxNode>, Arc<ExpansionSpanMap>)>;
#[salsa::transparent]
+ #[salsa::invoke(SpanMap::new)]
fn span_map(&self, file_id: HirFileId) -> SpanMap;
+ #[salsa::invoke(crate::span_map::real_span_map)]
fn real_span_map(&self, file_id: FileId) -> Arc<RealSpanMap>;
/// Macro ids. That's probably the tricksiest bit in rust-analyzer, and the
@@ -173,6 +96,7 @@ pub trait ExpandDatabase: SourceDatabase {
#[salsa::transparent]
fn setup_syntax_context_root(&self) -> ();
#[salsa::transparent]
+ #[salsa::invoke(crate::hygiene::dump_syntax_contexts)]
fn dump_syntax_contexts(&self) -> String;
/// Lowers syntactic macro call to a token tree representation. That's a firewall
@@ -184,8 +108,10 @@ pub trait ExpandDatabase: SourceDatabase {
) -> ValueResult<Option<(Arc<tt::Subtree>, SyntaxFixupUndoInfo)>, Arc<Box<[SyntaxError]>>>;
/// Fetches the expander for this macro.
#[salsa::transparent]
+ #[salsa::invoke(TokenExpander::macro_expander)]
fn macro_expander(&self, id: MacroDefId) -> TokenExpander;
/// Fetches (and compiles) the expander of this decl macro.
+ #[salsa::invoke(DeclarativeMacroExpander::expander)]
fn decl_macro_expander(
&self,
def_crate: CrateId,
@@ -203,36 +129,6 @@ pub trait ExpandDatabase: SourceDatabase {
) -> ExpandResult<Box<[SyntaxError]>>;
}
-#[inline]
-pub fn span_map(db: &dyn ExpandDatabase, file_id: HirFileId) -> SpanMap {
- match file_id.repr() {
- HirFileIdRepr::FileId(file_id) => SpanMap::RealSpanMap(db.real_span_map(file_id)),
- HirFileIdRepr::MacroFile(m) => {
- SpanMap::ExpansionSpanMap(db.parse_macro_expansion(m).value.1)
- }
- }
-}
-
-pub fn real_span_map(db: &dyn ExpandDatabase, file_id: FileId) -> Arc<RealSpanMap> {
- use syntax::ast::HasModuleItem;
- let mut pairs = vec![(syntax::TextSize::new(0), span::ROOT_ERASED_FILE_AST_ID)];
- let ast_id_map = db.ast_id_map(file_id.into());
- let tree = db.parse(file_id).tree();
- // FIXME: Descend into modules and other item containing items that are not annotated with attributes
- // and allocate pairs for those as well. This gives us finer grained span anchors resulting in
- // better incrementality
- pairs.extend(
- tree.items()
- .map(|item| (item.syntax().text_range().start(), ast_id_map.ast_id(&item).erase())),
- );
-
- Arc::new(RealSpanMap::from_file(
- file_id,
- pairs.into_boxed_slice(),
- tree.syntax().text_range().end(),
- ))
-}
-
/// This expands the given macro call, but with different arguments. This is
/// used for completion, where we want to see what 'would happen' if we insert a
/// token. The `token_to_map` mapped down into the expansion, with the mapped
@@ -357,10 +253,6 @@ pub fn expand_speculative(
Some((node.syntax_node(), token))
}
-fn ast_id_map(db: &dyn ExpandDatabase, file_id: HirFileId) -> Arc<AstIdMap> {
- Arc::new(AstIdMap::from_source(&db.parse_or_expand(file_id)))
-}
-
fn parse_or_expand(db: &dyn ExpandDatabase, file_id: HirFileId) -> SyntaxNode {
match file_id.repr() {
HirFileIdRepr::FileId(file_id) => db.parse(file_id).syntax_node(),
@@ -412,7 +304,10 @@ fn parse_macro_expansion_error(
.map(|it| it.0.errors().to_vec().into_boxed_slice())
}
-fn parse_with_map(db: &dyn ExpandDatabase, file_id: HirFileId) -> (Parse<SyntaxNode>, SpanMap) {
+pub(crate) fn parse_with_map(
+ db: &dyn ExpandDatabase,
+ file_id: HirFileId,
+) -> (Parse<SyntaxNode>, SpanMap) {
match file_id.repr() {
HirFileIdRepr::FileId(file_id) => {
(db.parse(file_id).to_syntax(), SpanMap::RealSpanMap(db.real_span_map(file_id)))
@@ -581,100 +476,18 @@ fn censor_for_macro_input(loc: &MacroCallLoc, node: &SyntaxNode) -> FxHashSet<Sy
.unwrap_or_default()
}
-fn decl_macro_expander(
- db: &dyn ExpandDatabase,
- def_crate: CrateId,
- id: AstId<ast::Macro>,
-) -> Arc<DeclarativeMacroExpander> {
- let crate_data = &db.crate_graph()[def_crate];
- let is_2021 = crate_data.edition >= Edition::Edition2021;
- let (root, map) = parse_with_map(db, id.file_id);
- let root = root.syntax_node();
-
- let transparency = |node| {
- // ... would be nice to have the item tree here
- let attrs = RawAttrs::new(db, node, map.as_ref()).filter(db, def_crate);
- match &*attrs
- .iter()
- .find(|it| {
- it.path.as_ident().and_then(|it| it.as_str()) == Some("rustc_macro_transparency")
- })?
- .token_tree_value()?
- .token_trees
- {
- [tt::TokenTree::Leaf(tt::Leaf::Ident(i)), ..] => match &*i.text {
- "transparent" => Some(Transparency::Transparent),
- "semitransparent" => Some(Transparency::SemiTransparent),
- "opaque" => Some(Transparency::Opaque),
- _ => None,
- },
- _ => None,
- }
- };
- let toolchain = crate_data.toolchain.as_ref();
- let new_meta_vars = toolchain.as_ref().map_or(false, |version| {
- REQUIREMENT.get_or_init(|| VersionReq::parse(">=1.76").unwrap()).matches(
- &base_db::Version {
- pre: base_db::Prerelease::EMPTY,
- build: base_db::BuildMetadata::EMPTY,
- major: version.major,
- minor: version.minor,
- patch: version.patch,
- },
- )
- });
-
- let (mac, transparency) = match id.to_ptr(db).to_node(&root) {
- ast::Macro::MacroRules(macro_rules) => (
- match macro_rules.token_tree() {
- Some(arg) => {
- let tt = mbe::syntax_node_to_token_tree(
- arg.syntax(),
- map.as_ref(),
- map.span_for_range(macro_rules.macro_rules_token().unwrap().text_range()),
- );
-
- mbe::DeclarativeMacro::parse_macro_rules(&tt, is_2021, new_meta_vars)
- }
- None => mbe::DeclarativeMacro::from_err(
- mbe::ParseError::Expected("expected a token tree".into()),
- is_2021,
- ),
- },
- transparency(&macro_rules).unwrap_or(Transparency::SemiTransparent),
- ),
- ast::Macro::MacroDef(macro_def) => (
- match macro_def.body() {
- Some(arg) => {
- let tt = mbe::syntax_node_to_token_tree(
- arg.syntax(),
- map.as_ref(),
- map.span_for_range(macro_def.macro_token().unwrap().text_range()),
- );
-
- mbe::DeclarativeMacro::parse_macro2(&tt, is_2021, new_meta_vars)
- }
- None => mbe::DeclarativeMacro::from_err(
- mbe::ParseError::Expected("expected a token tree".into()),
- is_2021,
- ),
- },
- transparency(&macro_def).unwrap_or(Transparency::Opaque),
- ),
- };
- Arc::new(DeclarativeMacroExpander { mac, transparency })
-}
-
-fn macro_expander(db: &dyn ExpandDatabase, id: MacroDefId) -> TokenExpander {
- match id.kind {
- MacroDefKind::Declarative(ast_id) => {
- TokenExpander::DeclarativeMacro(db.decl_macro_expander(id.krate, ast_id))
+impl TokenExpander {
+ fn macro_expander(db: &dyn ExpandDatabase, id: MacroDefId) -> TokenExpander {
+ match id.kind {
+ MacroDefKind::Declarative(ast_id) => {
+ TokenExpander::DeclarativeMacro(db.decl_macro_expander(id.krate, ast_id))
+ }
+ MacroDefKind::BuiltIn(expander, _) => TokenExpander::BuiltIn(expander),
+ MacroDefKind::BuiltInAttr(expander, _) => TokenExpander::BuiltInAttr(expander),
+ MacroDefKind::BuiltInDerive(expander, _) => TokenExpander::BuiltInDerive(expander),
+ MacroDefKind::BuiltInEager(expander, ..) => TokenExpander::BuiltInEager(expander),
+ MacroDefKind::ProcMacro(expander, ..) => TokenExpander::ProcMacro(expander),
}
- MacroDefKind::BuiltIn(expander, _) => TokenExpander::BuiltIn(expander),
- MacroDefKind::BuiltInAttr(expander, _) => TokenExpander::BuiltInAttr(expander),
- MacroDefKind::BuiltInDerive(expander, _) => TokenExpander::BuiltInDerive(expander),
- MacroDefKind::BuiltInEager(expander, ..) => TokenExpander::BuiltInEager(expander),
- MacroDefKind::ProcMacro(expander, ..) => TokenExpander::ProcMacro(expander),
}
}
@@ -862,40 +675,3 @@ fn check_tt_count(tt: &tt::Subtree) -> Result<(), ExpandResult<()>> {
fn setup_syntax_context_root(db: &dyn ExpandDatabase) {
db.intern_syntax_context(SyntaxContextData::root());
}
-
-fn dump_syntax_contexts(db: &dyn ExpandDatabase) -> String {
- let mut s = String::from("Expansions:");
- let mut entries = InternMacroCallLookupQuery.in_db(db).entries::<Vec<_>>();
- entries.sort_by_key(|e| e.key);
- for e in entries {
- let id = e.key;
- let expn_data = e.value.as_ref().unwrap();
- s.push_str(&format!(
- "\n{:?}: parent: {:?}, call_site_ctxt: {:?}, def_site_ctxt: {:?}, kind: {:?}",
- id,
- expn_data.kind.file_id(),
- expn_data.call_site,
- SyntaxContextId::ROOT, // FIXME expn_data.def_site,
- expn_data.kind.descr(),
- ));
- }
-
- s.push_str("\n\nSyntaxContexts:\n");
- let mut entries = InternSyntaxContextLookupQuery.in_db(db).entries::<Vec<_>>();
- entries.sort_by_key(|e| e.key);
- for e in entries {
- struct SyntaxContextDebug<'a>(
- &'a dyn ExpandDatabase,
- SyntaxContextId,
- &'a SyntaxContextData,
- );
-
- impl<'a> std::fmt::Debug for SyntaxContextDebug<'a> {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- self.2.fancy_debug(self.1, self.0, f)
- }
- }
- stdx::format_to!(s, "{:?}\n", SyntaxContextDebug(db, e.key, &e.value.unwrap()));
- }
- s
-}