expand: Simplify expansion of derives
And make it more uniform with other macros. By merging placeholders for future derives' outputs into the derive container's output fragment early.
This commit is contained in:
parent
2d3c17a609
commit
7ce85f2dca
7 changed files with 28 additions and 40 deletions
|
|
@ -90,7 +90,7 @@ impl<'a> DefCollector<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn visit_macro_invoc(&mut self, id: NodeId) {
|
||||
fn visit_macro_invoc(&mut self, id: NodeId) {
|
||||
self.definitions.set_invocation_parent(id.placeholder_to_expn_id(), self.parent_def);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -163,25 +163,15 @@ impl<'a> Resolver<'a> {
|
|||
Some(ext)
|
||||
}
|
||||
|
||||
// FIXME: `extra_placeholders` should be included into the `fragment` as regular placeholders.
|
||||
crate fn build_reduced_graph(
|
||||
&mut self,
|
||||
fragment: &AstFragment,
|
||||
extra_placeholders: &[NodeId],
|
||||
parent_scope: ParentScope<'a>,
|
||||
) -> LegacyScope<'a> {
|
||||
let mut def_collector = DefCollector::new(&mut self.definitions, parent_scope.expansion);
|
||||
fragment.visit_with(&mut def_collector);
|
||||
for placeholder in extra_placeholders {
|
||||
def_collector.visit_macro_invoc(*placeholder);
|
||||
}
|
||||
|
||||
let mut visitor = BuildReducedGraphVisitor { r: self, parent_scope };
|
||||
fragment.visit_with(&mut visitor);
|
||||
for placeholder in extra_placeholders {
|
||||
visitor.parent_scope.legacy = visitor.visit_invoc(*placeholder);
|
||||
}
|
||||
|
||||
visitor.parent_scope.legacy
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -108,15 +108,11 @@ impl<'a> base::Resolver for Resolver<'a> {
|
|||
});
|
||||
}
|
||||
|
||||
// FIXME: `extra_placeholders` should be included into the `fragment` as regular placeholders.
|
||||
fn visit_ast_fragment_with_placeholders(
|
||||
&mut self, expansion: ExpnId, fragment: &AstFragment, extra_placeholders: &[NodeId]
|
||||
) {
|
||||
fn visit_ast_fragment_with_placeholders(&mut self, expansion: ExpnId, fragment: &AstFragment) {
|
||||
// Integrate the new AST fragment into all the definition and module structures.
|
||||
// We are inside the `expansion` now, but other parent scope components are still the same.
|
||||
let parent_scope = ParentScope { expansion, ..self.invocation_parent_scopes[&expansion] };
|
||||
let output_legacy_scope =
|
||||
self.build_reduced_graph(fragment, extra_placeholders, parent_scope);
|
||||
let output_legacy_scope = self.build_reduced_graph(fragment, parent_scope);
|
||||
self.output_legacy_scopes.insert(expansion, output_legacy_scope);
|
||||
|
||||
parent_scope.module.unexpanded_invocations.borrow_mut().remove(&expansion);
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#![feature(const_fn)]
|
||||
#![feature(const_transmute)]
|
||||
#![feature(crate_visibility_modifier)]
|
||||
#![feature(decl_macro)]
|
||||
#![feature(label_break_value)]
|
||||
#![feature(nll)]
|
||||
#![feature(try_trait)]
|
||||
|
|
|
|||
|
|
@ -851,8 +851,7 @@ pub trait Resolver {
|
|||
fn next_node_id(&mut self) -> NodeId;
|
||||
|
||||
fn resolve_dollar_crates(&mut self);
|
||||
fn visit_ast_fragment_with_placeholders(&mut self, expn_id: ExpnId, fragment: &AstFragment,
|
||||
extra_placeholders: &[NodeId]);
|
||||
fn visit_ast_fragment_with_placeholders(&mut self, expn_id: ExpnId, fragment: &AstFragment);
|
||||
fn register_builtin_macro(&mut self, ident: ast::Ident, ext: SyntaxExtension);
|
||||
|
||||
fn expansion_for_ast_pass(
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ use errors::{Applicability, FatalError};
|
|||
use smallvec::{smallvec, SmallVec};
|
||||
use syntax_pos::{Span, DUMMY_SP, FileName};
|
||||
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use std::io::ErrorKind;
|
||||
use std::{iter, mem, slice};
|
||||
|
|
@ -75,6 +74,22 @@ macro_rules! ast_fragments {
|
|||
}
|
||||
|
||||
impl AstFragment {
|
||||
pub fn add_placeholders(&mut self, placeholders: &[NodeId]) {
|
||||
if placeholders.is_empty() {
|
||||
return;
|
||||
}
|
||||
match self {
|
||||
$($(AstFragment::$Kind(ast) => ast.extend(placeholders.iter().flat_map(|id| {
|
||||
// We are repeating through arguments with `many`, to do that we have to
|
||||
// mention some macro variable from those arguments even if it's not used.
|
||||
#[cfg_attr(bootstrap, allow(unused_macros))]
|
||||
macro _repeating($flat_map_ast_elt) {}
|
||||
placeholder(AstFragmentKind::$Kind, *id).$make_ast()
|
||||
})),)?)*
|
||||
_ => panic!("unexpected AST fragment kind")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn make_opt_expr(self) -> Option<P<ast::Expr>> {
|
||||
match self {
|
||||
AstFragment::OptExpr(expr) => expr,
|
||||
|
|
@ -342,7 +357,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
// Unresolved macros produce dummy outputs as a recovery measure.
|
||||
invocations.reverse();
|
||||
let mut expanded_fragments = Vec::new();
|
||||
let mut all_derive_placeholders: FxHashMap<ExpnId, Vec<_>> = FxHashMap::default();
|
||||
let mut undetermined_invocations = Vec::new();
|
||||
let (mut progress, mut force) = (false, !self.monotonic);
|
||||
loop {
|
||||
|
|
@ -420,9 +434,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
self.cx.resolver.add_derives(invoc.expansion_data.id, SpecialDerives::COPY);
|
||||
}
|
||||
|
||||
let derive_placeholders =
|
||||
all_derive_placeholders.entry(invoc.expansion_data.id).or_default();
|
||||
derive_placeholders.reserve(derives.len());
|
||||
let mut derive_placeholders = Vec::with_capacity(derives.len());
|
||||
invocations.reserve(derives.len());
|
||||
for path in derives {
|
||||
let expn_id = ExpnId::fresh(None);
|
||||
|
|
@ -438,7 +450,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
}
|
||||
let fragment = invoc.fragment_kind
|
||||
.expect_from_annotatables(::std::iter::once(item));
|
||||
self.collect_invocations(fragment, derive_placeholders)
|
||||
self.collect_invocations(fragment, &derive_placeholders)
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -457,10 +469,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
let mut placeholder_expander = PlaceholderExpander::new(self.cx, self.monotonic);
|
||||
while let Some(expanded_fragments) = expanded_fragments.pop() {
|
||||
for (expn_id, expanded_fragment) in expanded_fragments.into_iter().rev() {
|
||||
let derive_placeholders =
|
||||
all_derive_placeholders.remove(&expn_id).unwrap_or_else(Vec::new);
|
||||
placeholder_expander.add(NodeId::placeholder_from_expn_id(expn_id),
|
||||
expanded_fragment, derive_placeholders);
|
||||
expanded_fragment);
|
||||
}
|
||||
}
|
||||
fragment_with_placeholders.mut_visit_with(&mut placeholder_expander);
|
||||
|
|
@ -493,13 +503,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
monotonic: self.monotonic,
|
||||
};
|
||||
fragment.mut_visit_with(&mut collector);
|
||||
fragment.add_placeholders(extra_placeholders);
|
||||
collector.invocations
|
||||
};
|
||||
|
||||
// FIXME: Merge `extra_placeholders` into the `fragment` as regular placeholders.
|
||||
if self.monotonic {
|
||||
self.cx.resolver.visit_ast_fragment_with_placeholders(
|
||||
self.cx.current_expansion.id, &fragment, extra_placeholders);
|
||||
self.cx.current_expansion.id, &fragment
|
||||
);
|
||||
}
|
||||
|
||||
(fragment, invocations)
|
||||
|
|
|
|||
|
|
@ -171,17 +171,8 @@ impl<'a, 'b> PlaceholderExpander<'a, 'b> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn add(&mut self, id: ast::NodeId, mut fragment: AstFragment, placeholders: Vec<NodeId>) {
|
||||
pub fn add(&mut self, id: ast::NodeId, mut fragment: AstFragment) {
|
||||
fragment.mut_visit_with(self);
|
||||
if let AstFragment::Items(mut items) = fragment {
|
||||
for placeholder in placeholders {
|
||||
match self.remove(placeholder) {
|
||||
AstFragment::Items(derived_items) => items.extend(derived_items),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
fragment = AstFragment::Items(items);
|
||||
}
|
||||
self.expanded_fragments.insert(id, fragment);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue