expand: Merge expand_{bang,attr,derive}_invoc
into a single function
It's more convenient to have all this highly related stuff together on one screen (for future refactorings). The `expand_invoc` function is compact enough now, after all the previous refactorings.
This commit is contained in:
parent
374a80a86d
commit
b003dd6d9b
@ -327,7 +327,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||||||
|
|
||||||
// FIXME(jseyfried): Refactor out the following logic
|
// FIXME(jseyfried): Refactor out the following logic
|
||||||
let (expanded_fragment, new_invocations) = if let Some(ext) = ext {
|
let (expanded_fragment, new_invocations) = if let Some(ext) = ext {
|
||||||
let fragment = self.expand_invoc(invoc, &ext);
|
let fragment = self.expand_invoc(invoc, &ext.kind);
|
||||||
self.collect_invocations(fragment, &[])
|
self.collect_invocations(fragment, &[])
|
||||||
} else if let InvocationKind::Attr { attr: None, traits, item, .. } = invoc.kind {
|
} else if let InvocationKind::Attr { attr: None, traits, item, .. } = invoc.kind {
|
||||||
if !item.derive_allowed() {
|
if !item.derive_allowed() {
|
||||||
@ -474,12 +474,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expand_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtension) -> AstFragment {
|
fn expand_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtensionKind) -> AstFragment {
|
||||||
if invoc.fragment_kind == AstFragmentKind::ForeignItems &&
|
let (fragment_kind, span) = (invoc.fragment_kind, invoc.span());
|
||||||
!self.cx.ecfg.macros_in_extern() {
|
if fragment_kind == AstFragmentKind::ForeignItems && !self.cx.ecfg.macros_in_extern() {
|
||||||
if let SyntaxExtensionKind::NonMacroAttr { .. } = ext.kind {} else {
|
if let SyntaxExtensionKind::NonMacroAttr { .. } = ext {} else {
|
||||||
emit_feature_err(&self.cx.parse_sess, sym::macros_in_extern,
|
emit_feature_err(&self.cx.parse_sess, sym::macros_in_extern,
|
||||||
invoc.span(), GateIssue::Language,
|
span, GateIssue::Language,
|
||||||
"macro invocations in `extern {}` blocks are experimental");
|
"macro invocations in `extern {}` blocks are experimental");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -499,58 +499,84 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
match invoc.kind {
|
match invoc.kind {
|
||||||
InvocationKind::Bang { .. } => self.expand_bang_invoc(invoc, ext),
|
InvocationKind::Bang { mac, .. } => match ext {
|
||||||
InvocationKind::Attr { .. } => self.expand_attr_invoc(invoc, ext),
|
SyntaxExtensionKind::Bang(expander) => {
|
||||||
InvocationKind::Derive { .. } => self.expand_derive_invoc(invoc, ext),
|
self.gate_proc_macro_expansion_kind(span, fragment_kind);
|
||||||
}
|
let tok_result = expander.expand(self.cx, span, mac.node.stream());
|
||||||
}
|
let result =
|
||||||
|
self.parse_ast_fragment(tok_result, fragment_kind, &mac.node.path, span);
|
||||||
fn expand_attr_invoc(&mut self,
|
self.gate_proc_macro_expansion(span, &result);
|
||||||
invoc: Invocation,
|
result
|
||||||
ext: &SyntaxExtension)
|
|
||||||
-> AstFragment {
|
|
||||||
let (attr, mut item) = match invoc.kind {
|
|
||||||
InvocationKind::Attr { attr: Some(attr), item, .. } => (attr, item),
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
|
|
||||||
match &ext.kind {
|
|
||||||
SyntaxExtensionKind::NonMacroAttr { mark_used } => {
|
|
||||||
attr::mark_known(&attr);
|
|
||||||
if *mark_used {
|
|
||||||
attr::mark_used(&attr);
|
|
||||||
}
|
}
|
||||||
item.visit_attrs(|attrs| attrs.push(attr));
|
SyntaxExtensionKind::LegacyBang(expander) => {
|
||||||
invoc.fragment_kind.expect_from_annotatables(iter::once(item))
|
let tok_result = expander.expand(self.cx, span, mac.node.stream());
|
||||||
}
|
if let Some(result) = fragment_kind.make_from(tok_result) {
|
||||||
SyntaxExtensionKind::LegacyAttr(expander) => {
|
result
|
||||||
match attr.parse_meta(self.cx.parse_sess) {
|
} else {
|
||||||
Ok(meta) => {
|
let msg = format!("non-{kind} macro in {kind} position: {path}",
|
||||||
let item = expander.expand(self.cx, attr.span, &meta, item);
|
kind = fragment_kind.name(), path = mac.node.path);
|
||||||
invoc.fragment_kind.expect_from_annotatables(item)
|
self.cx.span_err(span, &msg);
|
||||||
}
|
self.cx.trace_macros_diag();
|
||||||
Err(mut err) => {
|
fragment_kind.dummy(span)
|
||||||
err.emit();
|
|
||||||
invoc.fragment_kind.dummy(attr.span)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_ => unreachable!()
|
||||||
}
|
}
|
||||||
SyntaxExtensionKind::Attr(expander) => {
|
InvocationKind::Attr { attr: Some(attr), mut item, .. } => match ext {
|
||||||
self.gate_proc_macro_attr_item(attr.span, &item);
|
SyntaxExtensionKind::Attr(expander) => {
|
||||||
let item_tok = TokenTree::token(token::Interpolated(Lrc::new(match item {
|
self.gate_proc_macro_attr_item(span, &item);
|
||||||
Annotatable::Item(item) => token::NtItem(item),
|
let item_tok = TokenTree::token(token::Interpolated(Lrc::new(match item {
|
||||||
Annotatable::TraitItem(item) => token::NtTraitItem(item.into_inner()),
|
Annotatable::Item(item) => token::NtItem(item),
|
||||||
Annotatable::ImplItem(item) => token::NtImplItem(item.into_inner()),
|
Annotatable::TraitItem(item) => token::NtTraitItem(item.into_inner()),
|
||||||
Annotatable::ForeignItem(item) => token::NtForeignItem(item.into_inner()),
|
Annotatable::ImplItem(item) => token::NtImplItem(item.into_inner()),
|
||||||
Annotatable::Stmt(stmt) => token::NtStmt(stmt.into_inner()),
|
Annotatable::ForeignItem(item) => token::NtForeignItem(item.into_inner()),
|
||||||
Annotatable::Expr(expr) => token::NtExpr(expr),
|
Annotatable::Stmt(stmt) => token::NtStmt(stmt.into_inner()),
|
||||||
})), DUMMY_SP).into();
|
Annotatable::Expr(expr) => token::NtExpr(expr),
|
||||||
let input = self.extract_proc_macro_attr_input(attr.tokens, attr.span);
|
})), DUMMY_SP).into();
|
||||||
let tok_result = expander.expand(self.cx, attr.span, input, item_tok);
|
let input = self.extract_proc_macro_attr_input(attr.tokens, span);
|
||||||
let res = self.parse_ast_fragment(tok_result, invoc.fragment_kind,
|
let tok_result = expander.expand(self.cx, span, input, item_tok);
|
||||||
&attr.path, attr.span);
|
let res = self.parse_ast_fragment(tok_result, fragment_kind, &attr.path, span);
|
||||||
self.gate_proc_macro_expansion(attr.span, &res);
|
self.gate_proc_macro_expansion(span, &res);
|
||||||
res
|
res
|
||||||
|
}
|
||||||
|
SyntaxExtensionKind::LegacyAttr(expander) => {
|
||||||
|
match attr.parse_meta(self.cx.parse_sess) {
|
||||||
|
Ok(meta) => {
|
||||||
|
let item = expander.expand(self.cx, span, &meta, item);
|
||||||
|
fragment_kind.expect_from_annotatables(item)
|
||||||
|
}
|
||||||
|
Err(mut err) => {
|
||||||
|
err.emit();
|
||||||
|
fragment_kind.dummy(span)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SyntaxExtensionKind::NonMacroAttr { mark_used } => {
|
||||||
|
attr::mark_known(&attr);
|
||||||
|
if *mark_used {
|
||||||
|
attr::mark_used(&attr);
|
||||||
|
}
|
||||||
|
item.visit_attrs(|attrs| attrs.push(attr));
|
||||||
|
fragment_kind.expect_from_annotatables(iter::once(item))
|
||||||
|
}
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
InvocationKind::Derive { path, item, item_with_markers } => match ext {
|
||||||
|
SyntaxExtensionKind::Derive(expander) |
|
||||||
|
SyntaxExtensionKind::LegacyDerive(expander) => {
|
||||||
|
let (path, item) = match ext {
|
||||||
|
SyntaxExtensionKind::LegacyDerive(..) => (path, item_with_markers),
|
||||||
|
_ => (path, item),
|
||||||
|
};
|
||||||
|
if !item.derive_allowed() {
|
||||||
|
return fragment_kind.dummy(span);
|
||||||
|
}
|
||||||
|
let meta = ast::MetaItem { node: ast::MetaItemKind::Word, span, path };
|
||||||
|
let span = span.with_ctxt(self.cx.backtrace());
|
||||||
|
let items = expander.expand(self.cx, span, &meta, item);
|
||||||
|
fragment_kind.expect_from_annotatables(items)
|
||||||
|
}
|
||||||
|
_ => unreachable!()
|
||||||
}
|
}
|
||||||
_ => unreachable!()
|
_ => unreachable!()
|
||||||
}
|
}
|
||||||
@ -634,42 +660,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Expand a macro invocation. Returns the resulting expanded AST fragment.
|
|
||||||
fn expand_bang_invoc(&mut self,
|
|
||||||
invoc: Invocation,
|
|
||||||
ext: &SyntaxExtension)
|
|
||||||
-> AstFragment {
|
|
||||||
let kind = invoc.fragment_kind;
|
|
||||||
let (mac, span) = match invoc.kind {
|
|
||||||
InvocationKind::Bang { mac, span } => (mac, span),
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
let path = &mac.node.path;
|
|
||||||
|
|
||||||
match &ext.kind {
|
|
||||||
SyntaxExtensionKind::Bang(expander) => {
|
|
||||||
self.gate_proc_macro_expansion_kind(span, kind);
|
|
||||||
let tok_result = expander.expand(self.cx, span, mac.node.stream());
|
|
||||||
let result = self.parse_ast_fragment(tok_result, kind, path, span);
|
|
||||||
self.gate_proc_macro_expansion(span, &result);
|
|
||||||
result
|
|
||||||
}
|
|
||||||
SyntaxExtensionKind::LegacyBang(expander) => {
|
|
||||||
let tok_result = expander.expand(self.cx, span, mac.node.stream());
|
|
||||||
if let Some(result) = kind.make_from(tok_result) {
|
|
||||||
result
|
|
||||||
} else {
|
|
||||||
let msg = format!("non-{kind} macro in {kind} position: {name}",
|
|
||||||
name = path.segments[0].ident.name, kind = kind.name());
|
|
||||||
self.cx.span_err(path.span, &msg);
|
|
||||||
self.cx.trace_macros_diag();
|
|
||||||
kind.dummy(span)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gate_proc_macro_expansion_kind(&self, span: Span, kind: AstFragmentKind) {
|
fn gate_proc_macro_expansion_kind(&self, span: Span, kind: AstFragmentKind) {
|
||||||
let kind = match kind {
|
let kind = match kind {
|
||||||
AstFragmentKind::Expr => "expressions",
|
AstFragmentKind::Expr => "expressions",
|
||||||
@ -694,34 +684,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Expand a derive invocation. Returns the resulting expanded AST fragment.
|
|
||||||
fn expand_derive_invoc(&mut self,
|
|
||||||
invoc: Invocation,
|
|
||||||
ext: &SyntaxExtension)
|
|
||||||
-> AstFragment {
|
|
||||||
let (path, item) = match invoc.kind {
|
|
||||||
InvocationKind::Derive { path, item, item_with_markers } => match ext.kind {
|
|
||||||
SyntaxExtensionKind::LegacyDerive(..) => (path, item_with_markers),
|
|
||||||
_ => (path, item),
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
if !item.derive_allowed() {
|
|
||||||
return invoc.fragment_kind.dummy(path.span);
|
|
||||||
}
|
|
||||||
|
|
||||||
match &ext.kind {
|
|
||||||
SyntaxExtensionKind::Derive(expander) |
|
|
||||||
SyntaxExtensionKind::LegacyDerive(expander) => {
|
|
||||||
let meta = ast::MetaItem { node: ast::MetaItemKind::Word, span: path.span, path };
|
|
||||||
let span = meta.span.with_ctxt(self.cx.backtrace());
|
|
||||||
let items = expander.expand(self.cx, span, &meta, item);
|
|
||||||
invoc.fragment_kind.expect_from_annotatables(items)
|
|
||||||
}
|
|
||||||
_ => unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_ast_fragment(&mut self,
|
fn parse_ast_fragment(&mut self,
|
||||||
toks: TokenStream,
|
toks: TokenStream,
|
||||||
kind: AstFragmentKind,
|
kind: AstFragmentKind,
|
||||||
|
@ -8,7 +8,7 @@ error: non-type macro in type position: cfg
|
|||||||
--> $DIR/macro-error.rs:8:12
|
--> $DIR/macro-error.rs:8:12
|
||||||
|
|
|
|
||||||
LL | let _: cfg!(foo) = ();
|
LL | let _: cfg!(foo) = ();
|
||||||
| ^^^
|
| ^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user