mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-28 12:54:58 +00:00
Auto merge of #16835 - wyatt-herkamp:use_one_tt_for_a_derive, r=Veykril
Have Derive Attribute share a token tree with it's proc macros. The goal of this PR is to stop creating a token tree for each derive proc macro. This is done by giving the derive proc macros an id to its parent derive element. From running the analysis stat on the rust analyzer project I did see a small memory decrease. ``` Inference: 42.80s, 362ginstr, 591mb MIR lowering: 8.67s, 67ginstr, 291mb Mir failed bodies: 18 (0%) Data layouts: 85.81ms, 609minstr, 8mb Failed data layouts: 135 (6%) Const evaluation: 440.57ms, 5235minstr, 13mb Failed const evals: 1 (0%) Total: 64.16s, 552ginstr, 1731mb ``` After Change ``` Inference: 40.32s, 340ginstr, 593mb MIR lowering: 7.95s, 62ginstr, 292mb Mir failed bodies: 18 (0%) Data layouts: 87.97ms, 591minstr, 8mb Failed data layouts: 135 (6%) Const evaluation: 433.38ms, 5226minstr, 14mb Failed const evals: 1 (0%) Total: 60.49s, 523ginstr, 1680mb ``` Currently this breaks the expansion for the actual derive attribute. ## TODO - [x] Pick a better name for the function `smart_macro_arg`
This commit is contained in:
commit
16c8deeb86
6 changed files with 80 additions and 32 deletions
|
@ -136,6 +136,7 @@ pub(super) fn derive_macro_as_call_id(
|
||||||
call_site: SyntaxContextId,
|
call_site: SyntaxContextId,
|
||||||
krate: CrateId,
|
krate: CrateId,
|
||||||
resolver: impl Fn(path::ModPath) -> Option<(MacroId, MacroDefId)>,
|
resolver: impl Fn(path::ModPath) -> Option<(MacroId, MacroDefId)>,
|
||||||
|
derive_macro_id: MacroCallId,
|
||||||
) -> Result<(MacroId, MacroDefId, MacroCallId), UnresolvedMacro> {
|
) -> Result<(MacroId, MacroDefId, MacroCallId), UnresolvedMacro> {
|
||||||
let (macro_id, def_id) = resolver(item_attr.path.clone())
|
let (macro_id, def_id) = resolver(item_attr.path.clone())
|
||||||
.filter(|(_, def_id)| def_id.is_derive())
|
.filter(|(_, def_id)| def_id.is_derive())
|
||||||
|
@ -147,6 +148,7 @@ pub(super) fn derive_macro_as_call_id(
|
||||||
ast_id: item_attr.ast_id,
|
ast_id: item_attr.ast_id,
|
||||||
derive_index: derive_pos,
|
derive_index: derive_pos,
|
||||||
derive_attr_index,
|
derive_attr_index,
|
||||||
|
derive_macro_id,
|
||||||
},
|
},
|
||||||
call_site,
|
call_site,
|
||||||
);
|
);
|
||||||
|
|
|
@ -237,6 +237,8 @@ enum MacroDirectiveKind {
|
||||||
derive_attr: AttrId,
|
derive_attr: AttrId,
|
||||||
derive_pos: usize,
|
derive_pos: usize,
|
||||||
ctxt: SyntaxContextId,
|
ctxt: SyntaxContextId,
|
||||||
|
/// The "parent" macro it is resolved to.
|
||||||
|
derive_macro_id: MacroCallId,
|
||||||
},
|
},
|
||||||
Attr {
|
Attr {
|
||||||
ast_id: AstIdWithPath<ast::Item>,
|
ast_id: AstIdWithPath<ast::Item>,
|
||||||
|
@ -1146,7 +1148,13 @@ impl DefCollector<'_> {
|
||||||
return Resolved::Yes;
|
return Resolved::Yes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MacroDirectiveKind::Derive { ast_id, derive_attr, derive_pos, ctxt: call_site } => {
|
MacroDirectiveKind::Derive {
|
||||||
|
ast_id,
|
||||||
|
derive_attr,
|
||||||
|
derive_pos,
|
||||||
|
ctxt: call_site,
|
||||||
|
derive_macro_id,
|
||||||
|
} => {
|
||||||
let id = derive_macro_as_call_id(
|
let id = derive_macro_as_call_id(
|
||||||
self.db,
|
self.db,
|
||||||
ast_id,
|
ast_id,
|
||||||
|
@ -1155,6 +1163,7 @@ impl DefCollector<'_> {
|
||||||
*call_site,
|
*call_site,
|
||||||
self.def_map.krate,
|
self.def_map.krate,
|
||||||
resolver,
|
resolver,
|
||||||
|
*derive_macro_id,
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Ok((macro_id, def_id, call_id)) = id {
|
if let Ok((macro_id, def_id, call_id)) = id {
|
||||||
|
@ -1224,6 +1233,8 @@ impl DefCollector<'_> {
|
||||||
_ => return Resolved::No,
|
_ => return Resolved::No,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let call_id =
|
||||||
|
attr_macro_as_call_id(self.db, file_ast_id, attr, self.def_map.krate, def);
|
||||||
if let MacroDefId {
|
if let MacroDefId {
|
||||||
kind:
|
kind:
|
||||||
MacroDefKind::BuiltInAttr(
|
MacroDefKind::BuiltInAttr(
|
||||||
|
@ -1252,6 +1263,7 @@ impl DefCollector<'_> {
|
||||||
return recollect_without(self);
|
return recollect_without(self);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let ast_id = ast_id.with_value(ast_adt_id);
|
let ast_id = ast_id.with_value(ast_adt_id);
|
||||||
|
|
||||||
match attr.parse_path_comma_token_tree(self.db.upcast()) {
|
match attr.parse_path_comma_token_tree(self.db.upcast()) {
|
||||||
|
@ -1267,6 +1279,7 @@ impl DefCollector<'_> {
|
||||||
derive_attr: attr.id,
|
derive_attr: attr.id,
|
||||||
derive_pos: idx,
|
derive_pos: idx,
|
||||||
ctxt: call_site.ctx,
|
ctxt: call_site.ctx,
|
||||||
|
derive_macro_id: call_id,
|
||||||
},
|
},
|
||||||
container: directive.container,
|
container: directive.container,
|
||||||
});
|
});
|
||||||
|
@ -1301,10 +1314,6 @@ impl DefCollector<'_> {
|
||||||
return recollect_without(self);
|
return recollect_without(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not resolved to a derive helper or the derive attribute, so try to treat as a normal attribute.
|
|
||||||
let call_id =
|
|
||||||
attr_macro_as_call_id(self.db, file_ast_id, attr, self.def_map.krate, def);
|
|
||||||
|
|
||||||
// Skip #[test]/#[bench] expansion, which would merely result in more memory usage
|
// Skip #[test]/#[bench] expansion, which would merely result in more memory usage
|
||||||
// due to duplicating functions into macro expansions
|
// due to duplicating functions into macro expansions
|
||||||
if matches!(
|
if matches!(
|
||||||
|
@ -1460,13 +1469,20 @@ impl DefCollector<'_> {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MacroDirectiveKind::Derive { ast_id, derive_attr, derive_pos, ctxt: _ } => {
|
MacroDirectiveKind::Derive {
|
||||||
|
ast_id,
|
||||||
|
derive_attr,
|
||||||
|
derive_pos,
|
||||||
|
derive_macro_id,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
self.def_map.diagnostics.push(DefDiagnostic::unresolved_macro_call(
|
self.def_map.diagnostics.push(DefDiagnostic::unresolved_macro_call(
|
||||||
directive.module_id,
|
directive.module_id,
|
||||||
MacroCallKind::Derive {
|
MacroCallKind::Derive {
|
||||||
ast_id: ast_id.ast_id,
|
ast_id: ast_id.ast_id,
|
||||||
derive_attr_index: *derive_attr,
|
derive_attr_index: *derive_attr,
|
||||||
derive_index: *derive_pos as u32,
|
derive_index: *derive_pos as u32,
|
||||||
|
derive_macro_id: *derive_macro_id,
|
||||||
},
|
},
|
||||||
ast_id.path.clone(),
|
ast_id.path.clone(),
|
||||||
));
|
));
|
||||||
|
|
|
@ -10,7 +10,7 @@ use syntax::{
|
||||||
use tracing::{debug, warn};
|
use tracing::{debug, warn};
|
||||||
use tt::SmolStr;
|
use tt::SmolStr;
|
||||||
|
|
||||||
use crate::{db::ExpandDatabase, MacroCallKind, MacroCallLoc};
|
use crate::{db::ExpandDatabase, proc_macro::ProcMacroKind, MacroCallLoc, MacroDefKind};
|
||||||
|
|
||||||
fn check_cfg_attr(attr: &Attr, loc: &MacroCallLoc, db: &dyn ExpandDatabase) -> Option<bool> {
|
fn check_cfg_attr(attr: &Attr, loc: &MacroCallLoc, db: &dyn ExpandDatabase) -> Option<bool> {
|
||||||
if !attr.simple_name().as_deref().map(|v| v == "cfg")? {
|
if !attr.simple_name().as_deref().map(|v| v == "cfg")? {
|
||||||
|
@ -180,7 +180,13 @@ pub(crate) fn process_cfg_attrs(
|
||||||
db: &dyn ExpandDatabase,
|
db: &dyn ExpandDatabase,
|
||||||
) -> Option<FxHashSet<SyntaxElement>> {
|
) -> Option<FxHashSet<SyntaxElement>> {
|
||||||
// FIXME: #[cfg_eval] is not implemented. But it is not stable yet
|
// FIXME: #[cfg_eval] is not implemented. But it is not stable yet
|
||||||
if !matches!(loc.kind, MacroCallKind::Derive { .. }) {
|
let is_derive = match loc.def.kind {
|
||||||
|
MacroDefKind::BuiltInDerive(..)
|
||||||
|
| MacroDefKind::ProcMacro(_, ProcMacroKind::CustomDerive, _) => true,
|
||||||
|
MacroDefKind::BuiltInAttr(expander, _) => expander.is_derive(),
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
if !is_derive {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let mut remove = FxHashSet::default();
|
let mut remove = FxHashSet::default();
|
||||||
|
|
|
@ -24,7 +24,8 @@ use crate::{
|
||||||
HirFileId, HirFileIdRepr, MacroCallId, MacroCallKind, MacroCallLoc, MacroDefId, MacroDefKind,
|
HirFileId, HirFileIdRepr, MacroCallId, MacroCallKind, MacroCallLoc, MacroDefId, MacroDefKind,
|
||||||
MacroFileId,
|
MacroFileId,
|
||||||
};
|
};
|
||||||
|
/// This is just to ensure the types of smart_macro_arg and macro_arg are the same
|
||||||
|
type MacroArgResult = (Arc<tt::Subtree>, SyntaxFixupUndoInfo, Span);
|
||||||
/// Total limit on the number of tokens produced by any macro invocation.
|
/// Total limit on the number of tokens produced by any macro invocation.
|
||||||
///
|
///
|
||||||
/// If an invocation produces more tokens than this limit, it will not be stored in the database and
|
/// If an invocation produces more tokens than this limit, it will not be stored in the database and
|
||||||
|
@ -98,7 +99,13 @@ pub trait ExpandDatabase: SourceDatabase {
|
||||||
/// Lowers syntactic macro call to a token tree representation. That's a firewall
|
/// Lowers syntactic macro call to a token tree representation. That's a firewall
|
||||||
/// query, only typing in the macro call itself changes the returned
|
/// query, only typing in the macro call itself changes the returned
|
||||||
/// subtree.
|
/// subtree.
|
||||||
fn macro_arg(&self, id: MacroCallId) -> (Arc<tt::Subtree>, SyntaxFixupUndoInfo, Span);
|
fn macro_arg(&self, id: MacroCallId) -> MacroArgResult;
|
||||||
|
#[salsa::transparent]
|
||||||
|
fn macro_arg_considering_derives(
|
||||||
|
&self,
|
||||||
|
id: MacroCallId,
|
||||||
|
kind: &MacroCallKind,
|
||||||
|
) -> MacroArgResult;
|
||||||
/// Fetches the expander for this macro.
|
/// Fetches the expander for this macro.
|
||||||
#[salsa::transparent]
|
#[salsa::transparent]
|
||||||
#[salsa::invoke(TokenExpander::macro_expander)]
|
#[salsa::invoke(TokenExpander::macro_expander)]
|
||||||
|
@ -144,7 +151,7 @@ pub fn expand_speculative(
|
||||||
let span_map = RealSpanMap::absolute(FileId::BOGUS);
|
let span_map = RealSpanMap::absolute(FileId::BOGUS);
|
||||||
let span_map = SpanMapRef::RealSpanMap(&span_map);
|
let span_map = SpanMapRef::RealSpanMap(&span_map);
|
||||||
|
|
||||||
let (_, _, span) = db.macro_arg(actual_macro_call);
|
let (_, _, span) = db.macro_arg_considering_derives(actual_macro_call, &loc.kind);
|
||||||
|
|
||||||
// Build the subtree and token mapping for the speculative args
|
// Build the subtree and token mapping for the speculative args
|
||||||
let (mut tt, undo_info) = match loc.kind {
|
let (mut tt, undo_info) = match loc.kind {
|
||||||
|
@ -339,12 +346,24 @@ pub(crate) fn parse_with_map(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: for derive attributes, this will return separate copies of the same structures! Though
|
/// This resolves the [MacroCallId] to check if it is a derive macro if so get the [macro_arg] for the derive.
|
||||||
// they may differ in spans due to differing call sites...
|
/// Other wise return the [macro_arg] for the macro_call_id.
|
||||||
fn macro_arg(
|
///
|
||||||
|
/// This is not connected to the database so it does not cached the result. However, the inner [macro_arg] query is
|
||||||
|
fn macro_arg_considering_derives(
|
||||||
db: &dyn ExpandDatabase,
|
db: &dyn ExpandDatabase,
|
||||||
id: MacroCallId,
|
id: MacroCallId,
|
||||||
) -> (Arc<tt::Subtree>, SyntaxFixupUndoInfo, Span) {
|
kind: &MacroCallKind,
|
||||||
|
) -> MacroArgResult {
|
||||||
|
match kind {
|
||||||
|
// Get the macro arg for the derive macro
|
||||||
|
MacroCallKind::Derive { derive_macro_id, .. } => db.macro_arg(*derive_macro_id),
|
||||||
|
// Normal macro arg
|
||||||
|
_ => db.macro_arg(id),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn macro_arg(db: &dyn ExpandDatabase, id: MacroCallId) -> MacroArgResult {
|
||||||
let loc = db.lookup_intern_macro_call(id);
|
let loc = db.lookup_intern_macro_call(id);
|
||||||
|
|
||||||
if let MacroCallLoc {
|
if let MacroCallLoc {
|
||||||
|
@ -414,29 +433,30 @@ fn macro_arg(
|
||||||
}
|
}
|
||||||
return (Arc::new(tt), SyntaxFixupUndoInfo::NONE, span);
|
return (Arc::new(tt), SyntaxFixupUndoInfo::NONE, span);
|
||||||
}
|
}
|
||||||
MacroCallKind::Derive { ast_id, derive_attr_index, .. } => {
|
// MacroCallKind::Derive should not be here. As we are getting the argument for the derive macro
|
||||||
let node = ast_id.to_ptr(db).to_node(&root);
|
MacroCallKind::Derive { .. } => {
|
||||||
let censor_derive_input = censor_derive_input(derive_attr_index, &node);
|
unreachable!("`ExpandDatabase::macro_arg` called with `MacroCallKind::Derive`")
|
||||||
let item_node = node.into();
|
|
||||||
let attr_source = attr_source(derive_attr_index, &item_node);
|
|
||||||
// FIXME: This is wrong, this should point to the path of the derive attribute`
|
|
||||||
let span =
|
|
||||||
map.span_for_range(attr_source.as_ref().and_then(|it| it.path()).map_or_else(
|
|
||||||
|| item_node.syntax().text_range(),
|
|
||||||
|it| it.syntax().text_range(),
|
|
||||||
));
|
|
||||||
(censor_derive_input, item_node, span)
|
|
||||||
}
|
}
|
||||||
MacroCallKind::Attr { ast_id, invoc_attr_index, .. } => {
|
MacroCallKind::Attr { ast_id, invoc_attr_index, .. } => {
|
||||||
let node = ast_id.to_ptr(db).to_node(&root);
|
let node = ast_id.to_ptr(db).to_node(&root);
|
||||||
let attr_source = attr_source(invoc_attr_index, &node);
|
let attr_source = attr_source(invoc_attr_index, &node);
|
||||||
|
|
||||||
let span = map.span_for_range(
|
let span = map.span_for_range(
|
||||||
attr_source
|
attr_source
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|it| it.path())
|
.and_then(|it| it.path())
|
||||||
.map_or_else(|| node.syntax().text_range(), |it| it.syntax().text_range()),
|
.map_or_else(|| node.syntax().text_range(), |it| it.syntax().text_range()),
|
||||||
);
|
);
|
||||||
(attr_source.into_iter().map(|it| it.syntax().clone().into()).collect(), node, span)
|
// If derive attribute we need to censor the derive input
|
||||||
|
if matches!(loc.def.kind, MacroDefKind::BuiltInAttr(expander, ..) if expander.is_derive())
|
||||||
|
&& ast::Adt::can_cast(node.syntax().kind())
|
||||||
|
{
|
||||||
|
let adt = ast::Adt::cast(node.syntax().clone()).unwrap();
|
||||||
|
let censor_derive_input = censor_derive_input(invoc_attr_index, &adt);
|
||||||
|
(censor_derive_input, node, span)
|
||||||
|
} else {
|
||||||
|
(attr_source.into_iter().map(|it| it.syntax().clone().into()).collect(), node, span)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -526,7 +546,8 @@ fn macro_expand(
|
||||||
let (ExpandResult { value: tt, err }, span) = match loc.def.kind {
|
let (ExpandResult { value: tt, err }, span) = match loc.def.kind {
|
||||||
MacroDefKind::ProcMacro(..) => return db.expand_proc_macro(macro_call_id).map(CowArc::Arc),
|
MacroDefKind::ProcMacro(..) => return db.expand_proc_macro(macro_call_id).map(CowArc::Arc),
|
||||||
_ => {
|
_ => {
|
||||||
let (macro_arg, undo_info, span) = db.macro_arg(macro_call_id);
|
let (macro_arg, undo_info, span) =
|
||||||
|
db.macro_arg_considering_derives(macro_call_id, &loc.kind);
|
||||||
|
|
||||||
let arg = &*macro_arg;
|
let arg = &*macro_arg;
|
||||||
let res =
|
let res =
|
||||||
|
@ -603,7 +624,7 @@ fn proc_macro_span(db: &dyn ExpandDatabase, ast: AstId<ast::Fn>) -> Span {
|
||||||
|
|
||||||
fn expand_proc_macro(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult<Arc<tt::Subtree>> {
|
fn expand_proc_macro(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult<Arc<tt::Subtree>> {
|
||||||
let loc = db.lookup_intern_macro_call(id);
|
let loc = db.lookup_intern_macro_call(id);
|
||||||
let (macro_arg, undo_info, span) = db.macro_arg(id);
|
let (macro_arg, undo_info, span) = db.macro_arg_considering_derives(id, &loc.kind);
|
||||||
|
|
||||||
let (expander, ast) = match loc.def.kind {
|
let (expander, ast) = match loc.def.kind {
|
||||||
MacroDefKind::ProcMacro(expander, _, ast) => (expander, ast),
|
MacroDefKind::ProcMacro(expander, _, ast) => (expander, ast),
|
||||||
|
|
|
@ -224,6 +224,9 @@ pub enum MacroCallKind {
|
||||||
derive_attr_index: AttrId,
|
derive_attr_index: AttrId,
|
||||||
/// Index of the derive macro in the derive attribute
|
/// Index of the derive macro in the derive attribute
|
||||||
derive_index: u32,
|
derive_index: u32,
|
||||||
|
/// The "parent" macro call.
|
||||||
|
/// We will resolve the same token tree for all derive macros in the same derive attribute.
|
||||||
|
derive_macro_id: MacroCallId,
|
||||||
},
|
},
|
||||||
Attr {
|
Attr {
|
||||||
ast_id: AstId<ast::Item>,
|
ast_id: AstId<ast::Item>,
|
||||||
|
|
|
@ -972,7 +972,7 @@ fn precise_macro_call_location(
|
||||||
MacroKind::ProcMacro,
|
MacroKind::ProcMacro,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
MacroCallKind::Derive { ast_id, derive_attr_index, derive_index } => {
|
MacroCallKind::Derive { ast_id, derive_attr_index, derive_index, .. } => {
|
||||||
let node = ast_id.to_node(db.upcast());
|
let node = ast_id.to_node(db.upcast());
|
||||||
// Compute the precise location of the macro name's token in the derive
|
// Compute the precise location of the macro name's token in the derive
|
||||||
// list.
|
// list.
|
||||||
|
@ -3708,7 +3708,7 @@ impl Impl {
|
||||||
let macro_file = src.file_id.macro_file()?;
|
let macro_file = src.file_id.macro_file()?;
|
||||||
let loc = macro_file.macro_call_id.lookup(db.upcast());
|
let loc = macro_file.macro_call_id.lookup(db.upcast());
|
||||||
let (derive_attr, derive_index) = match loc.kind {
|
let (derive_attr, derive_index) = match loc.kind {
|
||||||
MacroCallKind::Derive { ast_id, derive_attr_index, derive_index } => {
|
MacroCallKind::Derive { ast_id, derive_attr_index, derive_index, .. } => {
|
||||||
let module_id = self.id.lookup(db.upcast()).container;
|
let module_id = self.id.lookup(db.upcast()).container;
|
||||||
(
|
(
|
||||||
db.crate_def_map(module_id.krate())[module_id.local_id]
|
db.crate_def_map(module_id.krate())[module_id.local_id]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue