Skip to content

Commit 3908913

Browse files
authored
Auto merge of #34253 - jseyfried:improve_multi_modifiers, r=nrc
Allow `MultiItemModifier`s to expand into zero or many items Fixes #34223. r? @nrc
2 parents 4960f2f + 58372af commit 3908913

File tree

4 files changed

+77
-100
lines changed

4 files changed

+77
-100
lines changed

src/libsyntax/ext/base.rs

+32-27
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ pub use self::SyntaxExtension::*;
1212

1313
use ast;
1414
use ast::{Name, PatKind};
15+
use attr::HasAttrs;
1516
use codemap;
1617
use codemap::{CodeMap, Span, ExpnId, ExpnInfo, NO_EXPANSION};
1718
use errors::DiagnosticBuilder;
@@ -40,29 +41,31 @@ pub enum Annotatable {
4041
ImplItem(P<ast::ImplItem>),
4142
}
4243

43-
impl Annotatable {
44-
pub fn attrs(&self) -> &[ast::Attribute] {
44+
impl HasAttrs for Annotatable {
45+
fn attrs(&self) -> &[ast::Attribute] {
4546
match *self {
46-
Annotatable::Item(ref i) => &i.attrs,
47-
Annotatable::TraitItem(ref ti) => &ti.attrs,
48-
Annotatable::ImplItem(ref ii) => &ii.attrs,
47+
Annotatable::Item(ref item) => &item.attrs,
48+
Annotatable::TraitItem(ref trait_item) => &trait_item.attrs,
49+
Annotatable::ImplItem(ref impl_item) => &impl_item.attrs,
4950
}
5051
}
5152

52-
pub fn fold_attrs(self, attrs: Vec<ast::Attribute>) -> Annotatable {
53+
fn map_attrs<F: FnOnce(Vec<ast::Attribute>) -> Vec<ast::Attribute>>(self, f: F) -> Self {
5354
match self {
54-
Annotatable::Item(i) => Annotatable::Item(i.map(|i| ast::Item {
55-
attrs: attrs,
56-
..i
57-
})),
58-
Annotatable::TraitItem(i) => Annotatable::TraitItem(i.map(|ti| {
59-
ast::TraitItem { attrs: attrs, ..ti }
60-
})),
61-
Annotatable::ImplItem(i) => Annotatable::ImplItem(i.map(|ii| {
62-
ast::ImplItem { attrs: attrs, ..ii }
63-
})),
55+
Annotatable::Item(item) => Annotatable::Item(item.map_attrs(f)),
56+
Annotatable::TraitItem(trait_item) => Annotatable::TraitItem(trait_item.map_attrs(f)),
57+
Annotatable::ImplItem(impl_item) => Annotatable::ImplItem(impl_item.map_attrs(f)),
6458
}
6559
}
60+
}
61+
62+
impl Annotatable {
63+
pub fn attrs(&self) -> &[ast::Attribute] {
64+
HasAttrs::attrs(self)
65+
}
66+
pub fn fold_attrs(self, attrs: Vec<ast::Attribute>) -> Annotatable {
67+
self.map_attrs(|_| attrs)
68+
}
6669

6770
pub fn expect_item(self) -> P<ast::Item> {
6871
match self {
@@ -129,32 +132,34 @@ impl<F> MultiItemDecorator for F
129132
}
130133
}
131134

132-
// A more flexible ItemKind::Modifier (ItemKind::Modifier should go away, eventually, FIXME).
133-
// meta_item is the annotation, item is the item being modified, parent_item
134-
// is the impl or trait item is declared in if item is part of such a thing.
135+
// `meta_item` is the annotation, and `item` is the item being modified.
135136
// FIXME Decorators should follow the same pattern too.
136137
pub trait MultiItemModifier {
137138
fn expand(&self,
138139
ecx: &mut ExtCtxt,
139140
span: Span,
140141
meta_item: &ast::MetaItem,
141142
item: Annotatable)
142-
-> Annotatable;
143+
-> Vec<Annotatable>;
143144
}
144145

145-
impl<F> MultiItemModifier for F
146-
where F: Fn(&mut ExtCtxt,
147-
Span,
148-
&ast::MetaItem,
149-
Annotatable) -> Annotatable
146+
impl<F, T> MultiItemModifier for F
147+
where F: Fn(&mut ExtCtxt, Span, &ast::MetaItem, Annotatable) -> T,
148+
T: Into<Vec<Annotatable>>,
150149
{
151150
fn expand(&self,
152151
ecx: &mut ExtCtxt,
153152
span: Span,
154153
meta_item: &ast::MetaItem,
155154
item: Annotatable)
156-
-> Annotatable {
157-
(*self)(ecx, span, meta_item, item)
155+
-> Vec<Annotatable> {
156+
(*self)(ecx, span, meta_item, item).into()
157+
}
158+
}
159+
160+
impl Into<Vec<Annotatable>> for Annotatable {
161+
fn into(self) -> Vec<Annotatable> {
162+
vec![self]
158163
}
159164
}
160165

src/libsyntax/ext/expand.rs

+34-65
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use ast::{Local, Ident, Mac_, Name, SpannedIdent};
1313
use ast::{MacStmtStyle, Mrk, Stmt, StmtKind, ItemKind};
1414
use ast::TokenTree;
1515
use ast;
16+
use attr::HasAttrs;
1617
use ext::mtwt;
1718
use ext::build::AstBuilder;
1819
use attr;
@@ -724,11 +725,7 @@ impl<'a> Folder for PatIdentRenamer<'a> {
724725
}
725726
}
726727

727-
fn expand_annotatable(a: Annotatable,
728-
fld: &mut MacroExpander)
729-
-> SmallVector<Annotatable> {
730-
let a = expand_item_multi_modifier(a, fld);
731-
728+
fn expand_multi_modified(a: Annotatable, fld: &mut MacroExpander) -> SmallVector<Annotatable> {
732729
let new_items: SmallVector<Annotatable> = match a {
733730
Annotatable::Item(it) => match it.node {
734731
ast::ItemKind::Mac(..) => {
@@ -796,29 +793,6 @@ fn decorate(a: Annotatable, fld: &mut MacroExpander) -> SmallVector<Annotatable>
796793
new_items
797794
}
798795

799-
// Partition a set of attributes into one kind of attribute, and other kinds.
800-
macro_rules! partition {
801-
($fn_name: ident, $variant: ident) => {
802-
#[allow(deprecated)] // The `allow` is needed because the `Modifier` variant might be used.
803-
fn $fn_name(attrs: &[ast::Attribute],
804-
fld: &MacroExpander)
805-
-> (Vec<ast::Attribute>, Vec<ast::Attribute>) {
806-
attrs.iter().cloned().partition(|attr| {
807-
match fld.cx.syntax_env.find(intern(&attr.name())) {
808-
Some(rc) => match *rc {
809-
$variant(..) => true,
810-
_ => false
811-
},
812-
_ => false
813-
}
814-
})
815-
}
816-
}
817-
}
818-
819-
partition!(multi_modifiers, MultiModifier);
820-
821-
822796
fn expand_decorators(a: Annotatable,
823797
fld: &mut MacroExpander,
824798
decorator_items: &mut SmallVector<Annotatable>,
@@ -864,46 +838,41 @@ fn expand_decorators(a: Annotatable,
864838
}
865839
}
866840

867-
fn expand_item_multi_modifier(mut it: Annotatable,
868-
fld: &mut MacroExpander)
869-
-> Annotatable {
870-
let (modifiers, other_attrs) = multi_modifiers(it.attrs(), fld);
871-
872-
// Update the attrs, leave everything else alone. Is this mutation really a good idea?
873-
it = it.fold_attrs(other_attrs);
874-
875-
if modifiers.is_empty() {
876-
return it
877-
}
878-
879-
for attr in &modifiers {
880-
let mname = intern(&attr.name());
881-
882-
match fld.cx.syntax_env.find(mname) {
883-
Some(rc) => match *rc {
884-
MultiModifier(ref mac) => {
885-
attr::mark_used(attr);
886-
fld.cx.bt_push(ExpnInfo {
887-
call_site: attr.span,
888-
callee: NameAndSpan {
889-
format: MacroAttribute(mname),
890-
span: Some(attr.span),
891-
// attributes can do whatever they like,
892-
// for now
893-
allow_internal_unstable: true,
894-
}
895-
});
896-
it = mac.expand(fld.cx, attr.span, &attr.node.value, it);
897-
fld.cx.bt_pop();
841+
fn expand_annotatable(mut item: Annotatable, fld: &mut MacroExpander) -> SmallVector<Annotatable> {
842+
let mut multi_modifier = None;
843+
item = item.map_attrs(|mut attrs| {
844+
for i in 0..attrs.len() {
845+
if let Some(extension) = fld.cx.syntax_env.find(intern(&attrs[i].name())) {
846+
if let MultiModifier(..) = *extension {
847+
multi_modifier = Some((attrs.remove(i), extension));
848+
break;
898849
}
899-
_ => unreachable!()
900-
},
901-
_ => unreachable!()
850+
}
902851
}
903-
}
852+
attrs
853+
});
904854

905-
// Expansion may have added new ItemKind::Modifiers.
906-
expand_item_multi_modifier(it, fld)
855+
match multi_modifier {
856+
None => expand_multi_modified(item, fld),
857+
Some((attr, extension)) => match *extension {
858+
MultiModifier(ref mac) => {
859+
attr::mark_used(&attr);
860+
fld.cx.bt_push(ExpnInfo {
861+
call_site: attr.span,
862+
callee: NameAndSpan {
863+
format: MacroAttribute(intern(&attr.name())),
864+
span: Some(attr.span),
865+
// attributes can do whatever they like, for now
866+
allow_internal_unstable: true,
867+
}
868+
});
869+
let modified = mac.expand(fld.cx, attr.span, &attr.node.value, item);
870+
fld.cx.bt_pop();
871+
modified.into_iter().flat_map(|it| expand_annotatable(it, fld)).collect()
872+
}
873+
_ => unreachable!(),
874+
}
875+
}
907876
}
908877

909878
fn expand_impl_item(ii: ast::ImplItem, fld: &mut MacroExpander)

src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs

+9-8
Original file line numberDiff line numberDiff line change
@@ -62,15 +62,16 @@ fn expand_identity(cx: &mut ExtCtxt, _span: Span, tts: &[TokenTree])
6262
fn expand_into_foo_multi(cx: &mut ExtCtxt,
6363
sp: Span,
6464
attr: &MetaItem,
65-
it: Annotatable) -> Annotatable {
65+
it: Annotatable) -> Vec<Annotatable> {
6666
match it {
67-
Annotatable::Item(it) => {
67+
Annotatable::Item(it) => vec![
6868
Annotatable::Item(P(Item {
6969
attrs: it.attrs.clone(),
7070
..(*quote_item!(cx, enum Foo2 { Bar2, Baz2 }).unwrap()).clone()
71-
}))
72-
}
73-
Annotatable::ImplItem(it) => {
71+
})),
72+
Annotatable::Item(quote_item!(cx, enum Foo3 { Bar }).unwrap()),
73+
],
74+
Annotatable::ImplItem(it) => vec![
7475
quote_item!(cx, impl X { fn foo(&self) -> i32 { 42 } }).unwrap().and_then(|i| {
7576
match i.node {
7677
ItemKind::Impl(_, _, _, _, _, mut items) => {
@@ -79,8 +80,8 @@ fn expand_into_foo_multi(cx: &mut ExtCtxt,
7980
_ => unreachable!("impl parsed to something other than impl")
8081
}
8182
})
82-
}
83-
Annotatable::TraitItem(it) => {
83+
],
84+
Annotatable::TraitItem(it) => vec![
8485
quote_item!(cx, trait X { fn foo(&self) -> i32 { 0 } }).unwrap().and_then(|i| {
8586
match i.node {
8687
ItemKind::Trait(_, _, _, mut items) => {
@@ -89,7 +90,7 @@ fn expand_into_foo_multi(cx: &mut ExtCtxt,
8990
_ => unreachable!("trait parsed to something other than trait")
9091
}
9192
})
92-
}
93+
],
9394
}
9495
}
9596

src/test/run-pass-fulldeps/macro-crate.rs

+2
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ pub fn main() {
4040
assert_eq!(Foo2::Bar2, Foo2::Bar2);
4141
test(None::<Foo2>);
4242

43+
let _ = Foo3::Bar;
44+
4345
let x = 10i32;
4446
assert_eq!(x.foo(), 42);
4547
let x = 10u8;

0 commit comments

Comments
 (0)