mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-27 10:17:15 +00:00
Salsify the crate graph
I.e. make it not one giant input but multiple, for incrementality and decreased memory usage for Salsa 3 reasons.
This commit is contained in:
parent
44f18c3d05
commit
c94e9efbef
108 changed files with 3630 additions and 2512 deletions
|
|
@ -1,7 +1,7 @@
|
|||
//! A higher level attributes based on TokenTree, with also some shortcuts.
|
||||
use std::{borrow::Cow, fmt, ops};
|
||||
|
||||
use base_db::CrateId;
|
||||
use base_db::Crate;
|
||||
use cfg::CfgExpr;
|
||||
use either::Either;
|
||||
use intern::{sym, Interned, Symbol};
|
||||
|
|
@ -119,7 +119,7 @@ impl RawAttrs {
|
|||
|
||||
/// Processes `cfg_attr`s, returning the resulting semantic `Attrs`.
|
||||
// FIXME: This should return a different type, signaling it was filtered?
|
||||
pub fn filter(self, db: &dyn ExpandDatabase, krate: CrateId) -> RawAttrs {
|
||||
pub fn filter(self, db: &dyn ExpandDatabase, krate: Crate) -> RawAttrs {
|
||||
let has_cfg_attrs = self
|
||||
.iter()
|
||||
.any(|attr| attr.path.as_ident().is_some_and(|name| *name == sym::cfg_attr.clone()));
|
||||
|
|
@ -127,7 +127,7 @@ impl RawAttrs {
|
|||
return self;
|
||||
}
|
||||
|
||||
let crate_graph = db.crate_graph();
|
||||
let cfg_options = krate.cfg_options(db);
|
||||
let new_attrs =
|
||||
self.iter()
|
||||
.flat_map(|attr| -> SmallVec<[_; 1]> {
|
||||
|
|
@ -151,7 +151,6 @@ impl RawAttrs {
|
|||
|(idx, attr)| Attr::from_tt(db, attr, index.with_cfg_attr(idx)),
|
||||
);
|
||||
|
||||
let cfg_options = &crate_graph[krate].cfg_options;
|
||||
let cfg = TopSubtree::from_token_trees(subtree.top_subtree().delimiter, cfg);
|
||||
let cfg = CfgExpr::parse(&cfg);
|
||||
if cfg_options.check(&cfg) == Some(false) {
|
||||
|
|
|
|||
|
|
@ -231,7 +231,7 @@ fn assert_expand(
|
|||
let cond = expect_fragment(
|
||||
&mut iter,
|
||||
parser::PrefixEntryPoint::Expr,
|
||||
db.crate_graph()[id.lookup(db).krate].edition,
|
||||
id.lookup(db).krate.data(db).edition,
|
||||
tt.top_subtree().delimiter.delim_span(),
|
||||
);
|
||||
_ = iter.expect_char(',');
|
||||
|
|
@ -333,7 +333,7 @@ fn cfg_expand(
|
|||
) -> ExpandResult<tt::TopSubtree> {
|
||||
let loc = db.lookup_intern_macro_call(id);
|
||||
let expr = CfgExpr::parse(tt);
|
||||
let enabled = db.crate_graph()[loc.krate].cfg_options.check(&expr) != Some(false);
|
||||
let enabled = loc.krate.cfg_options(db).check(&expr) != Some(false);
|
||||
let expanded = if enabled { quote!(span=>true) } else { quote!(span=>false) };
|
||||
ExpandResult::ok(expanded)
|
||||
}
|
||||
|
|
@ -669,7 +669,7 @@ fn relative_file(
|
|||
if res == call_site && !allow_recursion {
|
||||
Err(ExpandError::other(err_span, format!("recursive inclusion of `{path_str}`")))
|
||||
} else {
|
||||
Ok(EditionedFileId::new(res, db.crate_graph()[lookup.krate].edition))
|
||||
Ok(EditionedFileId::new(res, lookup.krate.data(db).edition))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -812,7 +812,7 @@ fn include_str_expand(
|
|||
|
||||
fn get_env_inner(db: &dyn ExpandDatabase, arg_id: MacroCallId, key: &Symbol) -> Option<String> {
|
||||
let krate = db.lookup_intern_macro_call(arg_id).krate;
|
||||
db.crate_graph()[krate].env.get(key.as_str())
|
||||
krate.env(db).get(key.as_str())
|
||||
}
|
||||
|
||||
fn env_expand(
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
//! Processes out #[cfg] and #[cfg_attr] attributes from the input for the derive macro
|
||||
use std::iter::Peekable;
|
||||
|
||||
use base_db::CrateId;
|
||||
use base_db::Crate;
|
||||
use cfg::{CfgAtom, CfgExpr};
|
||||
use intern::{sym, Symbol};
|
||||
use rustc_hash::FxHashSet;
|
||||
|
|
@ -13,16 +13,16 @@ use tracing::{debug, warn};
|
|||
|
||||
use crate::{db::ExpandDatabase, proc_macro::ProcMacroKind, MacroCallLoc, MacroDefKind};
|
||||
|
||||
fn check_cfg(db: &dyn ExpandDatabase, attr: &Attr, krate: CrateId) -> Option<bool> {
|
||||
fn check_cfg(db: &dyn ExpandDatabase, attr: &Attr, krate: Crate) -> Option<bool> {
|
||||
if !attr.simple_name().as_deref().map(|v| v == "cfg")? {
|
||||
return None;
|
||||
}
|
||||
let cfg = parse_from_attr_token_tree(&attr.meta()?.token_tree()?)?;
|
||||
let enabled = db.crate_graph()[krate].cfg_options.check(&cfg) != Some(false);
|
||||
let enabled = krate.cfg_options(db).check(&cfg) != Some(false);
|
||||
Some(enabled)
|
||||
}
|
||||
|
||||
fn check_cfg_attr(db: &dyn ExpandDatabase, attr: &Attr, krate: CrateId) -> Option<bool> {
|
||||
fn check_cfg_attr(db: &dyn ExpandDatabase, attr: &Attr, krate: Crate) -> Option<bool> {
|
||||
if !attr.simple_name().as_deref().map(|v| v == "cfg_attr")? {
|
||||
return None;
|
||||
}
|
||||
|
|
@ -32,17 +32,17 @@ fn check_cfg_attr(db: &dyn ExpandDatabase, attr: &Attr, krate: CrateId) -> Optio
|
|||
pub fn check_cfg_attr_value(
|
||||
db: &dyn ExpandDatabase,
|
||||
attr: &TokenTree,
|
||||
krate: CrateId,
|
||||
krate: Crate,
|
||||
) -> Option<bool> {
|
||||
let cfg_expr = parse_from_attr_token_tree(attr)?;
|
||||
let enabled = db.crate_graph()[krate].cfg_options.check(&cfg_expr) != Some(false);
|
||||
let enabled = krate.cfg_options(db).check(&cfg_expr) != Some(false);
|
||||
Some(enabled)
|
||||
}
|
||||
|
||||
fn process_has_attrs_with_possible_comma<I: HasAttrs>(
|
||||
db: &dyn ExpandDatabase,
|
||||
items: impl Iterator<Item = I>,
|
||||
krate: CrateId,
|
||||
krate: Crate,
|
||||
remove: &mut FxHashSet<SyntaxElement>,
|
||||
) -> Option<()> {
|
||||
for item in items {
|
||||
|
|
@ -144,7 +144,7 @@ fn remove_possible_comma(item: &impl AstNode, res: &mut FxHashSet<SyntaxElement>
|
|||
fn process_enum(
|
||||
db: &dyn ExpandDatabase,
|
||||
variants: VariantList,
|
||||
krate: CrateId,
|
||||
krate: Crate,
|
||||
remove: &mut FxHashSet<SyntaxElement>,
|
||||
) -> Option<()> {
|
||||
'variant: for variant in variants.variants() {
|
||||
|
|
|
|||
|
|
@ -1,17 +1,16 @@
|
|||
//! Defines a unit of change that can applied to the database to get the next
|
||||
//! state. Changes are transactional.
|
||||
use base_db::{CrateGraph, CrateId, CrateWorkspaceData, FileChange, SourceRoot};
|
||||
use rustc_hash::FxHashMap;
|
||||
use base_db::{CrateGraphBuilder, FileChange, SourceRoot};
|
||||
use salsa::Durability;
|
||||
use span::FileId;
|
||||
use triomphe::Arc;
|
||||
|
||||
use crate::{db::ExpandDatabase, proc_macro::ProcMacros};
|
||||
use crate::{db::ExpandDatabase, proc_macro::ProcMacrosBuilder};
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct ChangeWithProcMacros {
|
||||
pub source_change: FileChange,
|
||||
pub proc_macros: Option<ProcMacros>,
|
||||
pub proc_macros: Option<ProcMacrosBuilder>,
|
||||
}
|
||||
|
||||
impl ChangeWithProcMacros {
|
||||
|
|
@ -20,8 +19,13 @@ impl ChangeWithProcMacros {
|
|||
}
|
||||
|
||||
pub fn apply(self, db: &mut impl ExpandDatabase) {
|
||||
self.source_change.apply(db);
|
||||
let crates_id_map = self.source_change.apply(db);
|
||||
if let Some(proc_macros) = self.proc_macros {
|
||||
let proc_macros = proc_macros.build(
|
||||
crates_id_map
|
||||
.as_ref()
|
||||
.expect("cannot set proc macros without setting the crate graph too"),
|
||||
);
|
||||
db.set_proc_macros_with_durability(Arc::new(proc_macros), Durability::HIGH);
|
||||
}
|
||||
}
|
||||
|
|
@ -30,16 +34,11 @@ impl ChangeWithProcMacros {
|
|||
self.source_change.change_file(file_id, new_text)
|
||||
}
|
||||
|
||||
pub fn set_crate_graph(
|
||||
&mut self,
|
||||
graph: CrateGraph,
|
||||
ws_data: FxHashMap<CrateId, Arc<CrateWorkspaceData>>,
|
||||
) {
|
||||
pub fn set_crate_graph(&mut self, graph: CrateGraphBuilder) {
|
||||
self.source_change.set_crate_graph(graph);
|
||||
self.source_change.set_ws_data(ws_data);
|
||||
}
|
||||
|
||||
pub fn set_proc_macros(&mut self, proc_macros: ProcMacros) {
|
||||
pub fn set_proc_macros(&mut self, proc_macros: ProcMacrosBuilder) {
|
||||
self.proc_macros = Some(proc_macros);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
//! Defines database & queries for macro expansion.
|
||||
|
||||
use base_db::{CrateId, RootQueryDb};
|
||||
use base_db::{Crate, RootQueryDb};
|
||||
use either::Either;
|
||||
use mbe::MatchedArmIndex;
|
||||
use rustc_hash::FxHashSet;
|
||||
|
|
@ -23,7 +23,7 @@ use crate::{
|
|||
span_with_call_site_ctxt, span_with_def_site_ctxt, span_with_mixed_site_ctxt,
|
||||
SyntaxContextExt as _,
|
||||
},
|
||||
proc_macro::{CustomProcMacroExpander, ProcMacros},
|
||||
proc_macro::{CrateProcMacros, CustomProcMacroExpander, ProcMacros},
|
||||
span_map::{ExpansionSpanMap, RealSpanMap, SpanMap, SpanMapRef},
|
||||
tt, AstId, BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerCallInfo,
|
||||
EagerExpander, ExpandError, ExpandResult, ExpandTo, MacroCallKind, MacroCallLoc, MacroDefId,
|
||||
|
|
@ -57,10 +57,13 @@ pub enum TokenExpander {
|
|||
|
||||
#[query_group::query_group]
|
||||
pub trait ExpandDatabase: RootQueryDb {
|
||||
/// The proc macros.
|
||||
/// The proc macros. Do not use this! Use `proc_macros_for_crate()` instead.
|
||||
#[salsa::input]
|
||||
fn proc_macros(&self) -> Arc<ProcMacros>;
|
||||
|
||||
#[salsa::invoke_actual(crate::proc_macro::proc_macros_for_crate)]
|
||||
fn proc_macros_for_crate(&self, krate: Crate) -> Option<Arc<CrateProcMacros>>;
|
||||
|
||||
fn ast_id_map(&self, file_id: HirFileId) -> Arc<AstIdMap>;
|
||||
|
||||
#[salsa::transparent]
|
||||
|
|
@ -120,7 +123,7 @@ pub trait ExpandDatabase: RootQueryDb {
|
|||
#[salsa::invoke(DeclarativeMacroExpander::expander)]
|
||||
fn decl_macro_expander(
|
||||
&self,
|
||||
def_crate: CrateId,
|
||||
def_crate: Crate,
|
||||
id: AstId<ast::Macro>,
|
||||
) -> Arc<DeclarativeMacroExpander>;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
//! Compiled declarative macro expanders (`macro_rules!` and `macro`)
|
||||
|
||||
use base_db::CrateId;
|
||||
use base_db::Crate;
|
||||
use intern::sym;
|
||||
use span::{Edition, HirFileIdRepr, MacroCallId, Span, SyntaxContextId};
|
||||
use stdx::TupleExt;
|
||||
|
|
@ -70,7 +70,7 @@ impl DeclarativeMacroExpander {
|
|||
|
||||
pub(crate) fn expander(
|
||||
db: &dyn ExpandDatabase,
|
||||
def_crate: CrateId,
|
||||
def_crate: Crate,
|
||||
id: AstId<ast::Macro>,
|
||||
) -> Arc<DeclarativeMacroExpander> {
|
||||
let (root, map) = crate::db::parse_with_map(db, id.file_id);
|
||||
|
|
@ -101,14 +101,12 @@ impl DeclarativeMacroExpander {
|
|||
}
|
||||
};
|
||||
let ctx_edition = |ctx: SyntaxContextId| {
|
||||
let crate_graph = db.crate_graph();
|
||||
|
||||
if ctx.is_root() {
|
||||
crate_graph[def_crate].edition
|
||||
def_crate.data(db).edition
|
||||
} else {
|
||||
// UNWRAP-SAFETY: Only the root context has no outer expansion
|
||||
let krate = db.lookup_intern_macro_call(ctx.outer_expn(db).unwrap()).def.krate;
|
||||
crate_graph[krate].edition
|
||||
krate.data(db).edition
|
||||
}
|
||||
};
|
||||
let (mac, transparency) = match id.to_ptr(db).to_node(&root) {
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
//!
|
||||
//!
|
||||
//! See the full discussion : <https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/Eager.20expansion.20of.20built-in.20macros>
|
||||
use base_db::CrateId;
|
||||
use base_db::Crate;
|
||||
use span::SyntaxContextId;
|
||||
use syntax::{ted, Parse, SyntaxElement, SyntaxNode, TextSize, WalkEvent};
|
||||
use syntax_bridge::DocCommentDesugarMode;
|
||||
|
|
@ -34,7 +34,7 @@ use crate::{
|
|||
|
||||
pub fn expand_eager_macro_input(
|
||||
db: &dyn ExpandDatabase,
|
||||
krate: CrateId,
|
||||
krate: Crate,
|
||||
macro_call: &ast::MacroCall,
|
||||
ast_id: AstId<ast::MacroCall>,
|
||||
def: MacroDefId,
|
||||
|
|
@ -115,7 +115,7 @@ fn lazy_expand(
|
|||
def: &MacroDefId,
|
||||
macro_call: &ast::MacroCall,
|
||||
ast_id: AstId<ast::MacroCall>,
|
||||
krate: CrateId,
|
||||
krate: Crate,
|
||||
call_site: SyntaxContextId,
|
||||
) -> ExpandResult<(InFile<Parse<SyntaxNode>>, Arc<ExpansionSpanMap>)> {
|
||||
let expand_to = ExpandTo::from_call_site(macro_call);
|
||||
|
|
@ -137,7 +137,7 @@ fn eager_macro_recur(
|
|||
expanded_map: &mut ExpansionSpanMap,
|
||||
mut offset: TextSize,
|
||||
curr: InFile<SyntaxNode>,
|
||||
krate: CrateId,
|
||||
krate: Crate,
|
||||
call_site: SyntaxContextId,
|
||||
macro_resolver: &dyn Fn(&ModPath) -> Option<MacroDefId>,
|
||||
) -> ExpandResult<Option<(SyntaxNode, TextSize)>> {
|
||||
|
|
@ -176,7 +176,7 @@ fn eager_macro_recur(
|
|||
Some(path) => match macro_resolver(&path) {
|
||||
Some(def) => def,
|
||||
None => {
|
||||
let edition = db.crate_graph()[krate].edition;
|
||||
let edition = krate.data(db).edition;
|
||||
error = Some(ExpandError::other(
|
||||
span_map.span_at(call.syntax().text_range().start()),
|
||||
format!("unresolved macro {}", path.display(db, edition)),
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ use triomphe::Arc;
|
|||
use core::fmt;
|
||||
use std::hash::Hash;
|
||||
|
||||
use base_db::CrateId;
|
||||
use base_db::Crate;
|
||||
use either::Either;
|
||||
use span::{
|
||||
Edition, EditionedFileId, ErasedFileAstId, FileAstId, HirFileIdRepr, Span, SpanAnchor,
|
||||
|
|
@ -157,7 +157,7 @@ impl ExpandError {
|
|||
pub enum ExpandErrorKind {
|
||||
/// Attribute macro expansion is disabled.
|
||||
ProcMacroAttrExpansionDisabled,
|
||||
MissingProcMacroExpander(CrateId),
|
||||
MissingProcMacroExpander(Crate),
|
||||
/// The macro for this call is disabled.
|
||||
MacroDisabled,
|
||||
/// The macro definition has errors.
|
||||
|
|
@ -200,7 +200,7 @@ impl ExpandErrorKind {
|
|||
kind: RenderedExpandError::DISABLED,
|
||||
},
|
||||
&ExpandErrorKind::MissingProcMacroExpander(def_crate) => {
|
||||
match db.proc_macros().get_error_for_crate(def_crate) {
|
||||
match db.proc_macros_for_crate(def_crate).as_ref().and_then(|it| it.get_error()) {
|
||||
Some((e, hard_err)) => RenderedExpandError {
|
||||
message: e.to_owned(),
|
||||
error: hard_err,
|
||||
|
|
@ -250,14 +250,14 @@ impl From<mbe::ExpandError> for ExpandError {
|
|||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct MacroCallLoc {
|
||||
pub def: MacroDefId,
|
||||
pub krate: CrateId,
|
||||
pub krate: Crate,
|
||||
pub kind: MacroCallKind,
|
||||
pub ctxt: SyntaxContextId,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct MacroDefId {
|
||||
pub krate: CrateId,
|
||||
pub krate: Crate,
|
||||
pub edition: Edition,
|
||||
pub kind: MacroDefKind,
|
||||
pub local_inner: bool,
|
||||
|
|
@ -525,7 +525,7 @@ impl MacroDefId {
|
|||
pub fn make_call(
|
||||
self,
|
||||
db: &dyn ExpandDatabase,
|
||||
krate: CrateId,
|
||||
krate: Crate,
|
||||
kind: MacroCallKind,
|
||||
ctxt: SyntaxContextId,
|
||||
) -> MacroCallId {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use crate::{
|
|||
name::{AsName, Name},
|
||||
tt,
|
||||
};
|
||||
use base_db::CrateId;
|
||||
use base_db::Crate;
|
||||
use intern::sym;
|
||||
use smallvec::SmallVec;
|
||||
use span::{Edition, SyntaxContextId};
|
||||
|
|
@ -33,7 +33,7 @@ pub enum PathKind {
|
|||
Abs,
|
||||
// FIXME: Can we remove this somehow?
|
||||
/// `$crate` from macro expansion
|
||||
DollarCrate(CrateId),
|
||||
DollarCrate(Crate),
|
||||
}
|
||||
|
||||
impl PathKind {
|
||||
|
|
@ -333,7 +333,7 @@ fn convert_path_tt(db: &dyn ExpandDatabase, tt: tt::TokenTreesView<'_>) -> Optio
|
|||
Some(ModPath { kind, segments })
|
||||
}
|
||||
|
||||
pub fn resolve_crate_root(db: &dyn ExpandDatabase, mut ctxt: SyntaxContextId) -> Option<CrateId> {
|
||||
pub fn resolve_crate_root(db: &dyn ExpandDatabase, mut ctxt: SyntaxContextId) -> Option<Crate> {
|
||||
// When resolving `$crate` from a `macro_rules!` invoked in a `macro`,
|
||||
// we don't want to pretend that the `macro_rules!` definition is in the `macro`
|
||||
// as described in `SyntaxContextId::apply_mark`, so we ignore prepended opaque marks.
|
||||
|
|
|
|||
|
|
@ -260,7 +260,7 @@ impl AsName for ast::FieldKind {
|
|||
}
|
||||
}
|
||||
|
||||
impl AsName for base_db::Dependency {
|
||||
impl AsName for base_db::BuiltDependency {
|
||||
fn as_name(&self) -> Name {
|
||||
Name::new_symbol_root((*self.name).clone())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
//! Pretty printing of macros output.
|
||||
|
||||
use base_db::CrateId;
|
||||
use base_db::Crate;
|
||||
use rustc_hash::FxHashMap;
|
||||
use syntax::NodeOrToken;
|
||||
use syntax::{ast::make, SyntaxNode};
|
||||
|
|
@ -13,13 +13,12 @@ pub fn prettify_macro_expansion(
|
|||
db: &dyn ExpandDatabase,
|
||||
syn: SyntaxNode,
|
||||
span_map: &ExpansionSpanMap,
|
||||
target_crate_id: CrateId,
|
||||
target_crate_id: Crate,
|
||||
) -> SyntaxNode {
|
||||
// Because `syntax_bridge::prettify_macro_expansion::prettify_macro_expansion()` clones subtree for `syn`,
|
||||
// that means it will be offsetted to the beginning.
|
||||
let span_offset = syn.text_range().start();
|
||||
let crate_graph = db.crate_graph();
|
||||
let target_crate = &crate_graph[target_crate_id];
|
||||
let target_crate = target_crate_id.data(db);
|
||||
let mut syntax_ctx_id_to_dollar_crate_replacement = FxHashMap::default();
|
||||
syntax_bridge::prettify_macro_expansion::prettify_macro_expansion(syn, &mut |dollar_crate| {
|
||||
let ctx = span_map.span_at(dollar_crate.text_range().start() + span_offset).ctx;
|
||||
|
|
@ -41,7 +40,7 @@ pub fn prettify_macro_expansion(
|
|||
target_crate.dependencies.iter().find(|dep| dep.crate_id == macro_def_crate)
|
||||
{
|
||||
make::tokens::ident(dep.name.as_str())
|
||||
} else if let Some(crate_name) = &crate_graph[macro_def_crate].display_name {
|
||||
} else if let Some(crate_name) = ¯o_def_crate.extra_data(db).display_name {
|
||||
make::tokens::ident(crate_name.crate_name().as_str())
|
||||
} else {
|
||||
return dollar_crate.clone();
|
||||
|
|
|
|||
|
|
@ -1,24 +1,36 @@
|
|||
//! Proc Macro Expander stuff
|
||||
|
||||
use core::fmt;
|
||||
use std::any::Any;
|
||||
use std::{panic::RefUnwindSafe, sync};
|
||||
|
||||
use base_db::{CrateId, Env};
|
||||
use base_db::{Crate, CrateBuilderId, CratesIdMap, Env};
|
||||
use intern::Symbol;
|
||||
use rustc_hash::FxHashMap;
|
||||
use span::Span;
|
||||
use triomphe::Arc;
|
||||
|
||||
use crate::{db::ExpandDatabase, tt, ExpandError, ExpandErrorKind, ExpandResult};
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)]
|
||||
#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Hash)]
|
||||
pub enum ProcMacroKind {
|
||||
CustomDerive,
|
||||
Bang,
|
||||
Attr,
|
||||
}
|
||||
|
||||
pub trait AsAny: Any {
|
||||
fn as_any(&self) -> &dyn Any;
|
||||
}
|
||||
|
||||
impl<T: Any> AsAny for T {
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// A proc-macro expander implementation.
|
||||
pub trait ProcMacroExpander: fmt::Debug + Send + Sync + RefUnwindSafe {
|
||||
pub trait ProcMacroExpander: fmt::Debug + Send + Sync + RefUnwindSafe + AsAny {
|
||||
/// Run the expander with the given input subtree, optional attribute input subtree (for
|
||||
/// [`ProcMacroKind::Attr`]), environment variables, and span information.
|
||||
fn expand(
|
||||
|
|
@ -31,8 +43,18 @@ pub trait ProcMacroExpander: fmt::Debug + Send + Sync + RefUnwindSafe {
|
|||
mixed_site: Span,
|
||||
current_dir: Option<String>,
|
||||
) -> Result<tt::TopSubtree, ProcMacroExpansionError>;
|
||||
|
||||
fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool;
|
||||
}
|
||||
|
||||
impl PartialEq for dyn ProcMacroExpander {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.eq_dyn(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for dyn ProcMacroExpander {}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ProcMacroExpansionError {
|
||||
/// The proc-macro panicked.
|
||||
|
|
@ -45,41 +67,68 @@ pub type ProcMacroLoadResult = Result<Vec<ProcMacro>, (String, bool)>;
|
|||
type StoredProcMacroLoadResult = Result<Box<[ProcMacro]>, (Box<str>, bool)>;
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct ProcMacrosBuilder(FxHashMap<CrateId, StoredProcMacroLoadResult>);
|
||||
pub struct ProcMacrosBuilder(FxHashMap<CrateBuilderId, Arc<CrateProcMacros>>);
|
||||
|
||||
impl ProcMacrosBuilder {
|
||||
pub fn insert(&mut self, proc_macros_crate: CrateId, proc_macro: ProcMacroLoadResult) {
|
||||
pub fn insert(
|
||||
&mut self,
|
||||
proc_macros_crate: CrateBuilderId,
|
||||
mut proc_macro: ProcMacroLoadResult,
|
||||
) {
|
||||
if let Ok(proc_macros) = &mut proc_macro {
|
||||
// Sort proc macros to improve incrementality when only their order has changed (ideally the build system
|
||||
// will not change their order, but just to be sure).
|
||||
proc_macros
|
||||
.sort_unstable_by_key(|proc_macro| (proc_macro.name.clone(), proc_macro.kind));
|
||||
}
|
||||
self.0.insert(
|
||||
proc_macros_crate,
|
||||
match proc_macro {
|
||||
Ok(it) => Ok(it.into_boxed_slice()),
|
||||
Err((e, hard_err)) => Err((e.into_boxed_str(), hard_err)),
|
||||
Ok(it) => Arc::new(CrateProcMacros(Ok(it.into_boxed_slice()))),
|
||||
Err((e, hard_err)) => {
|
||||
Arc::new(CrateProcMacros(Err((e.into_boxed_str(), hard_err))))
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
pub fn build(mut self) -> ProcMacros {
|
||||
self.0.shrink_to_fit();
|
||||
ProcMacros(self.0)
|
||||
|
||||
pub(crate) fn build(self, crates_id_map: &CratesIdMap) -> ProcMacros {
|
||||
let mut map = self
|
||||
.0
|
||||
.into_iter()
|
||||
.map(|(krate, proc_macro)| (crates_id_map[&krate], proc_macro))
|
||||
.collect::<FxHashMap<_, _>>();
|
||||
map.shrink_to_fit();
|
||||
ProcMacros(map)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct ProcMacros(FxHashMap<CrateId, StoredProcMacroLoadResult>);
|
||||
|
||||
impl FromIterator<(CrateId, ProcMacroLoadResult)> for ProcMacros {
|
||||
fn from_iter<T: IntoIterator<Item = (CrateId, ProcMacroLoadResult)>>(iter: T) -> Self {
|
||||
impl FromIterator<(CrateBuilderId, ProcMacroLoadResult)> for ProcMacrosBuilder {
|
||||
fn from_iter<T: IntoIterator<Item = (CrateBuilderId, ProcMacroLoadResult)>>(iter: T) -> Self {
|
||||
let mut builder = ProcMacrosBuilder::default();
|
||||
for (k, v) in iter {
|
||||
builder.insert(k, v);
|
||||
}
|
||||
builder.build()
|
||||
builder
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct CrateProcMacros(StoredProcMacroLoadResult);
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct ProcMacros(FxHashMap<Crate, Arc<CrateProcMacros>>);
|
||||
impl ProcMacros {
|
||||
fn get(&self, krate: CrateId, idx: u32, err_span: Span) -> Result<&ProcMacro, ExpandError> {
|
||||
let proc_macros = match self.0.get(&krate) {
|
||||
Some(Ok(proc_macros)) => proc_macros,
|
||||
Some(Err(_)) | None => {
|
||||
fn get(&self, krate: Crate) -> Option<Arc<CrateProcMacros>> {
|
||||
self.0.get(&krate).cloned()
|
||||
}
|
||||
}
|
||||
|
||||
impl CrateProcMacros {
|
||||
fn get(&self, idx: u32, err_span: Span) -> Result<&ProcMacro, ExpandError> {
|
||||
let proc_macros = match &self.0 {
|
||||
Ok(proc_macros) => proc_macros,
|
||||
Err(_) => {
|
||||
return Err(ExpandError::other(
|
||||
err_span,
|
||||
"internal error: no proc macros for crate",
|
||||
|
|
@ -98,18 +147,17 @@ impl ProcMacros {
|
|||
)
|
||||
}
|
||||
|
||||
pub fn get_error_for_crate(&self, krate: CrateId) -> Option<(&str, bool)> {
|
||||
self.0.get(&krate).and_then(|it| it.as_ref().err()).map(|(e, hard_err)| (&**e, *hard_err))
|
||||
pub fn get_error(&self) -> Option<(&str, bool)> {
|
||||
self.0.as_ref().err().map(|(e, hard_err)| (&**e, *hard_err))
|
||||
}
|
||||
|
||||
/// Fetch the [`CustomProcMacroExpander`]s and their corresponding names for the given crate.
|
||||
pub fn for_crate(
|
||||
pub fn list(
|
||||
&self,
|
||||
krate: CrateId,
|
||||
def_site_ctx: span::SyntaxContextId,
|
||||
) -> Option<Box<[(crate::name::Name, CustomProcMacroExpander, bool)]>> {
|
||||
match self.0.get(&krate) {
|
||||
Some(Ok(proc_macros)) => Some({
|
||||
match &self.0 {
|
||||
Ok(proc_macros) => Some(
|
||||
proc_macros
|
||||
.iter()
|
||||
.enumerate()
|
||||
|
|
@ -117,15 +165,15 @@ impl ProcMacros {
|
|||
let name = crate::name::Name::new_symbol(it.name.clone(), def_site_ctx);
|
||||
(name, CustomProcMacroExpander::new(idx as u32), it.disabled)
|
||||
})
|
||||
.collect()
|
||||
}),
|
||||
.collect(),
|
||||
),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A loaded proc-macro.
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Eq)]
|
||||
pub struct ProcMacro {
|
||||
/// The name of the proc macro.
|
||||
pub name: Symbol,
|
||||
|
|
@ -137,6 +185,23 @@ pub struct ProcMacro {
|
|||
pub disabled: bool,
|
||||
}
|
||||
|
||||
// `#[derive(PartialEq)]` generates a strange "cannot move" error.
|
||||
impl PartialEq for ProcMacro {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
let Self { name, kind, expander, disabled } = self;
|
||||
let Self {
|
||||
name: other_name,
|
||||
kind: other_kind,
|
||||
expander: other_expander,
|
||||
disabled: other_disabled,
|
||||
} = other;
|
||||
name == other_name
|
||||
&& kind == other_kind
|
||||
&& expander == other_expander
|
||||
&& disabled == other_disabled
|
||||
}
|
||||
}
|
||||
|
||||
/// A custom proc-macro expander handle. This handle together with its crate resolves to a [`ProcMacro`]
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
|
||||
pub struct CustomProcMacroExpander {
|
||||
|
|
@ -187,7 +252,7 @@ impl CustomProcMacroExpander {
|
|||
}
|
||||
|
||||
/// The macro is explicitly disabled due to proc-macro attribute expansion being disabled.
|
||||
pub fn as_expand_error(&self, def_crate: CrateId) -> Option<ExpandErrorKind> {
|
||||
pub fn as_expand_error(&self, def_crate: Crate) -> Option<ExpandErrorKind> {
|
||||
match self.proc_macro_id {
|
||||
Self::PROC_MACRO_ATTR_DISABLED => Some(ExpandErrorKind::ProcMacroAttrExpansionDisabled),
|
||||
Self::DISABLED_ID => Some(ExpandErrorKind::MacroDisabled),
|
||||
|
|
@ -199,8 +264,8 @@ impl CustomProcMacroExpander {
|
|||
pub fn expand(
|
||||
self,
|
||||
db: &dyn ExpandDatabase,
|
||||
def_crate: CrateId,
|
||||
calling_crate: CrateId,
|
||||
def_crate: Crate,
|
||||
calling_crate: Crate,
|
||||
tt: &tt::TopSubtree,
|
||||
attr_arg: Option<&tt::TopSubtree>,
|
||||
def_site: Span,
|
||||
|
|
@ -221,8 +286,22 @@ impl CustomProcMacroExpander {
|
|||
ExpandError::new(call_site, ExpandErrorKind::MacroDisabled),
|
||||
),
|
||||
id => {
|
||||
let proc_macros = db.proc_macros();
|
||||
let proc_macro = match proc_macros.get(def_crate, id, call_site) {
|
||||
let proc_macros = match db.proc_macros_for_crate(def_crate) {
|
||||
Some(it) => it,
|
||||
None => {
|
||||
return ExpandResult::new(
|
||||
tt::TopSubtree::empty(tt::DelimSpan {
|
||||
open: call_site,
|
||||
close: call_site,
|
||||
}),
|
||||
ExpandError::other(
|
||||
call_site,
|
||||
"internal error: no proc macros for crate",
|
||||
),
|
||||
)
|
||||
}
|
||||
};
|
||||
let proc_macro = match proc_macros.get(id, call_site) {
|
||||
Ok(proc_macro) => proc_macro,
|
||||
Err(e) => {
|
||||
return ExpandResult::new(
|
||||
|
|
@ -235,11 +314,10 @@ impl CustomProcMacroExpander {
|
|||
}
|
||||
};
|
||||
|
||||
let krate_graph = db.crate_graph();
|
||||
// Proc macros have access to the environment variables of the invoking crate.
|
||||
let env = &krate_graph[calling_crate].env;
|
||||
let env = calling_crate.env(db);
|
||||
let current_dir =
|
||||
krate_graph[calling_crate].proc_macro_cwd.as_deref().map(ToString::to_string);
|
||||
calling_crate.data(db).proc_macro_cwd.as_deref().map(ToString::to_string);
|
||||
|
||||
match proc_macro.expander.expand(
|
||||
tt,
|
||||
|
|
@ -278,3 +356,10 @@ impl CustomProcMacroExpander {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn proc_macros_for_crate(
|
||||
db: &dyn ExpandDatabase,
|
||||
krate: Crate,
|
||||
) -> Option<Arc<CrateProcMacros>> {
|
||||
db.proc_macros().get(krate)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue