WIP refactor expansion of decorators and move derive to MultiDecorator

This commit is contained in:
Nick Cameron 2015-04-28 17:34:39 +12:00
parent 0a4f9a2696
commit c0a42aecbc
16 changed files with 302 additions and 280 deletions

View file

@ -123,6 +123,16 @@ impl Annotatable {
}
}
pub fn map_item_or<F, G>(self, mut f: F, mut or: G) -> Annotatable
where F: FnMut(P<ast::Item>) -> P<ast::Item>,
G: FnMut(Annotatable) -> Annotatable
{
match self {
Annotatable::Item(i) => Annotatable::Item(f(i)),
_ => or(self)
}
}
pub fn expect_trait_item(self) -> P<ast::TraitItem> {
match self {
Annotatable::TraitItem(i) => i,
@ -144,18 +154,18 @@ pub trait MultiItemDecorator {
ecx: &mut ExtCtxt,
sp: Span,
meta_item: &ast::MetaItem,
item: &Annotatable,
push: &mut FnMut(Annotatable));
item: Annotatable,
push: &mut FnMut(Annotatable));
}
impl<F> MultiItemDecorator for F
where F : Fn(&mut ExtCtxt, Span, &ast::MetaItem, &Annotatable, &mut FnMut(Annotatable))
where F : Fn(&mut ExtCtxt, Span, &ast::MetaItem, Annotatable, &mut FnMut(Annotatable))
{
fn expand(&self,
ecx: &mut ExtCtxt,
sp: Span,
meta_item: &ast::MetaItem,
item: &Annotatable,
item: Annotatable,
push: &mut FnMut(Annotatable)) {
(*self)(ecx, sp, meta_item, item, push)
}
@ -433,6 +443,7 @@ pub enum SyntaxExtension {
/// based upon it.
#[unstable(feature = "rustc_private")]
#[deprecated(since = "1.0.0", reason = "replaced by MultiDecorator")]
#[allow(deprecated)]
Decorator(Box<ItemDecorator + 'static>),
/// A syntax extension that is attached to an item and creates new items
@ -445,6 +456,7 @@ pub enum SyntaxExtension {
/// in-place.
#[unstable(feature = "rustc_private")]
#[deprecated(since = "1.0.0", reason = "replaced by MultiModifier")]
#[allow(deprecated)]
Modifier(Box<ItemModifier + 'static>),
/// A syntax extension that is attached to an item and modifies it

View file

@ -8,18 +8,17 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use ast::{MetaItem, Item};
use ast::MetaItem;
use codemap::Span;
use ext::base::ExtCtxt;
use ext::base::{ExtCtxt, Annotatable};
use ext::deriving::generic::*;
use ext::deriving::generic::ty::*;
use ptr::P;
pub fn expand_deriving_unsafe_bound(cx: &mut ExtCtxt,
span: Span,
_: &MetaItem,
_: &Item,
_: &mut FnMut(P<Item>))
_: Annotatable,
_: &mut FnMut(Annotatable))
{
cx.span_err(span, "this unsafe trait should be implemented explicitly");
}
@ -27,8 +26,8 @@ pub fn expand_deriving_unsafe_bound(cx: &mut ExtCtxt,
pub fn expand_deriving_copy(cx: &mut ExtCtxt,
span: Span,
mitem: &MetaItem,
item: &Item,
push: &mut FnMut(P<Item>))
item: Annotatable,
push: &mut FnMut(Annotatable))
{
let path = Path::new(vec![
if cx.use_std { "std" } else { "core" },

View file

@ -8,9 +8,9 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use ast::{MetaItem, Item, Expr};
use ast::{MetaItem, Expr};
use codemap::Span;
use ext::base::ExtCtxt;
use ext::base::{ExtCtxt, Annotatable};
use ext::build::AstBuilder;
use ext::deriving::generic::*;
use ext::deriving::generic::ty::*;
@ -20,8 +20,8 @@ use ptr::P;
pub fn expand_deriving_clone(cx: &mut ExtCtxt,
span: Span,
mitem: &MetaItem,
item: &Item,
push: &mut FnMut(P<Item>))
item: Annotatable,
push: &mut FnMut(Annotatable))
{
let inline = cx.meta_word(span, InternedString::new("inline"));
let attrs = vec!(cx.attribute(span, inline));

View file

@ -8,9 +8,9 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use ast::{MetaItem, Item, Expr};
use ast::{MetaItem, Expr};
use codemap::Span;
use ext::base::ExtCtxt;
use ext::base::{ExtCtxt, Annotatable};
use ext::build::AstBuilder;
use ext::deriving::generic::*;
use ext::deriving::generic::ty::*;
@ -20,8 +20,8 @@ use ptr::P;
pub fn expand_deriving_eq(cx: &mut ExtCtxt,
span: Span,
mitem: &MetaItem,
item: &Item,
push: &mut FnMut(P<Item>))
item: Annotatable,
push: &mut FnMut(Annotatable))
{
fn cs_total_eq_assert(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P<Expr> {
cs_same_method(

View file

@ -9,9 +9,9 @@
// except according to those terms.
use ast;
use ast::{MetaItem, Item, Expr};
use ast::{MetaItem, Expr};
use codemap::Span;
use ext::base::ExtCtxt;
use ext::base::{ExtCtxt, Annotatable};
use ext::build::AstBuilder;
use ext::deriving::generic::*;
use ext::deriving::generic::ty::*;
@ -21,8 +21,8 @@ use ptr::P;
pub fn expand_deriving_ord(cx: &mut ExtCtxt,
span: Span,
mitem: &MetaItem,
item: &Item,
push: &mut FnMut(P<Item>))
item: Annotatable,
push: &mut FnMut(Annotatable))
{
let inline = cx.meta_word(span, InternedString::new("inline"));
let attrs = vec!(cx.attribute(span, inline));

View file

@ -8,9 +8,9 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use ast::{MetaItem, Item, Expr, self};
use ast::{MetaItem, Expr, self};
use codemap::Span;
use ext::base::ExtCtxt;
use ext::base::{ExtCtxt, Annotatable};
use ext::build::AstBuilder;
use ext::deriving::generic::*;
use ext::deriving::generic::ty::*;
@ -20,8 +20,8 @@ use ptr::P;
pub fn expand_deriving_partial_eq(cx: &mut ExtCtxt,
span: Span,
mitem: &MetaItem,
item: &Item,
push: &mut FnMut(P<Item>))
item: Annotatable,
push: &mut FnMut(Annotatable))
{
// structures are equal if all fields are equal, and non equal, if
// any fields are not equal or if the enum variants are different

View file

@ -11,9 +11,9 @@
pub use self::OrderingOp::*;
use ast;
use ast::{MetaItem, Item, Expr};
use ast::{MetaItem, Expr};
use codemap::Span;
use ext::base::ExtCtxt;
use ext::base::{ExtCtxt, Annotatable};
use ext::build::AstBuilder;
use ext::deriving::generic::*;
use ext::deriving::generic::ty::*;
@ -23,8 +23,8 @@ use ptr::P;
pub fn expand_deriving_partial_ord(cx: &mut ExtCtxt,
span: Span,
mitem: &MetaItem,
item: &Item,
push: &mut FnMut(P<Item>))
item: Annotatable,
push: &mut FnMut(Annotatable))
{
macro_rules! md {
($name:expr, $op:expr, $equal:expr) => { {

View file

@ -11,9 +11,9 @@
//! The compiler code necessary for `#[derive(Decodable)]`. See encodable.rs for more.
use ast;
use ast::{MetaItem, Item, Expr, MutMutable};
use ast::{MetaItem, Expr, MutMutable};
use codemap::Span;
use ext::base::ExtCtxt;
use ext::base::{ExtCtxt, Annotatable};
use ext::build::AstBuilder;
use ext::deriving::generic::*;
use ext::deriving::generic::ty::*;
@ -24,8 +24,8 @@ use ptr::P;
pub fn expand_deriving_rustc_decodable(cx: &mut ExtCtxt,
span: Span,
mitem: &MetaItem,
item: &Item,
push: &mut FnMut(P<Item>))
item: Annotatable,
push: &mut FnMut(Annotatable))
{
expand_deriving_decodable_imp(cx, span, mitem, item, push, "rustc_serialize")
}
@ -33,8 +33,8 @@ pub fn expand_deriving_rustc_decodable(cx: &mut ExtCtxt,
pub fn expand_deriving_decodable(cx: &mut ExtCtxt,
span: Span,
mitem: &MetaItem,
item: &Item,
push: &mut FnMut(P<Item>))
item: Annotatable,
push: &mut FnMut(Annotatable))
{
expand_deriving_decodable_imp(cx, span, mitem, item, push, "serialize")
}
@ -42,8 +42,8 @@ pub fn expand_deriving_decodable(cx: &mut ExtCtxt,
fn expand_deriving_decodable_imp(cx: &mut ExtCtxt,
span: Span,
mitem: &MetaItem,
item: &Item,
push: &mut FnMut(P<Item>),
item: Annotatable,
push: &mut FnMut(Annotatable),
krate: &'static str)
{
if !cx.use_std {

View file

@ -8,9 +8,9 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use ast::{MetaItem, Item, Expr};
use ast::{MetaItem, Expr};
use codemap::Span;
use ext::base::ExtCtxt;
use ext::base::{ExtCtxt, Annotatable};
use ext::build::AstBuilder;
use ext::deriving::generic::*;
use ext::deriving::generic::ty::*;
@ -20,8 +20,8 @@ use ptr::P;
pub fn expand_deriving_default(cx: &mut ExtCtxt,
span: Span,
mitem: &MetaItem,
item: &Item,
push: &mut FnMut(P<Item>))
item: Annotatable,
push: &mut FnMut(Annotatable))
{
let inline = cx.meta_word(span, InternedString::new("inline"));
let attrs = vec!(cx.attribute(span, inline));

View file

@ -88,9 +88,9 @@
//! }
//! ```
use ast::{MetaItem, Item, Expr, ExprRet, MutMutable};
use ast::{MetaItem, Expr, ExprRet, MutMutable};
use codemap::Span;
use ext::base::ExtCtxt;
use ext::base::{ExtCtxt,Annotatable};
use ext::build::AstBuilder;
use ext::deriving::generic::*;
use ext::deriving::generic::ty::*;
@ -100,8 +100,8 @@ use ptr::P;
pub fn expand_deriving_rustc_encodable(cx: &mut ExtCtxt,
span: Span,
mitem: &MetaItem,
item: &Item,
push: &mut FnMut(P<Item>))
item: Annotatable,
push: &mut FnMut(Annotatable))
{
expand_deriving_encodable_imp(cx, span, mitem, item, push, "rustc_serialize")
}
@ -109,8 +109,8 @@ pub fn expand_deriving_rustc_encodable(cx: &mut ExtCtxt,
pub fn expand_deriving_encodable(cx: &mut ExtCtxt,
span: Span,
mitem: &MetaItem,
item: &Item,
push: &mut FnMut(P<Item>))
item: Annotatable,
push: &mut FnMut(Annotatable))
{
expand_deriving_encodable_imp(cx, span, mitem, item, push, "serialize")
}
@ -118,8 +118,8 @@ pub fn expand_deriving_encodable(cx: &mut ExtCtxt,
fn expand_deriving_encodable_imp(cx: &mut ExtCtxt,
span: Span,
mitem: &MetaItem,
item: &Item,
push: &mut FnMut(P<Item>),
item: Annotatable,
push: &mut FnMut(Annotatable),
krate: &'static str)
{
if !cx.use_std {

View file

@ -197,7 +197,7 @@ use ast::{EnumDef, Expr, Ident, Generics, StructDef};
use ast_util;
use attr;
use attr::AttrMetaMethods;
use ext::base::ExtCtxt;
use ext::base::{ExtCtxt, Annotatable};
use ext::build::AstBuilder;
use codemap::{self, DUMMY_SP};
use codemap::Span;
@ -378,41 +378,48 @@ impl<'a> TraitDef<'a> {
pub fn expand(&self,
cx: &mut ExtCtxt,
mitem: &ast::MetaItem,
item: &ast::Item,
push: &mut FnMut(P<ast::Item>))
item: Annotatable,
push: &mut FnMut(Annotatable))
{
let newitem = match item.node {
ast::ItemStruct(ref struct_def, ref generics) => {
self.expand_struct_def(cx,
&**struct_def,
item.ident,
generics)
}
ast::ItemEnum(ref enum_def, ref generics) => {
self.expand_enum_def(cx,
enum_def,
&item.attrs[..],
item.ident,
generics)
match item {
Annotatable::Item(item) => {
let newitem = match item.node {
ast::ItemStruct(ref struct_def, ref generics) => {
self.expand_struct_def(cx,
&**struct_def,
item.ident,
generics)
}
ast::ItemEnum(ref enum_def, ref generics) => {
self.expand_enum_def(cx,
enum_def,
&item.attrs[..],
item.ident,
generics)
}
_ => {
cx.span_err(mitem.span, "`derive` may only be applied to structs and enums");
return;
}
};
// Keep the lint attributes of the previous item to control how the
// generated implementations are linted
let mut attrs = newitem.attrs.clone();
attrs.extend(item.attrs.iter().filter(|a| {
match &a.name()[..] {
"allow" | "warn" | "deny" | "forbid" => true,
_ => false,
}
}).cloned());
push(Annotatable::Item(P(ast::Item {
attrs: attrs,
..(*newitem).clone()
})))
}
_ => {
cx.span_err(mitem.span, "`derive` may only be applied to structs and enums");
return;
cx.span_err(mitem.span, "`derive` may only be applied to structs and enums");
}
};
// Keep the lint attributes of the previous item to control how the
// generated implementations are linted
let mut attrs = newitem.attrs.clone();
attrs.extend(item.attrs.iter().filter(|a| {
match &a.name()[..] {
"allow" | "warn" | "deny" | "forbid" => true,
_ => false,
}
}).cloned());
push(P(ast::Item {
attrs: attrs,
..(*newitem).clone()
}))
}
}
/// Given that we are deriving a trait `DerivedTrait` for a type like:

View file

@ -8,9 +8,9 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use ast::{MetaItem, Item, Expr, MutMutable};
use ast::{MetaItem, Expr, MutMutable};
use codemap::Span;
use ext::base::ExtCtxt;
use ext::base::{ExtCtxt, Annotatable};
use ext::build::AstBuilder;
use ext::deriving::generic::*;
use ext::deriving::generic::ty::*;
@ -19,8 +19,8 @@ use ptr::P;
pub fn expand_deriving_hash(cx: &mut ExtCtxt,
span: Span,
mitem: &MetaItem,
item: &Item,
push: &mut FnMut(P<Item>))
item: Annotatable,
push: &mut FnMut(Annotatable))
{
let path = Path::new_(pathvec_std!(cx, core::hash::Hash), None,

View file

@ -13,14 +13,13 @@
//! FIXME (#2810): hygiene. Search for "__" strings (in other files too). We also assume "extra" is
//! the standard library, and "std" is the core library.
use ast::{Item, MetaItem, MetaWord, MetaList, MetaNameValue};
use ast::{MetaItem, MetaWord};
use attr::AttrMetaMethods;
use ext::base::{ExtCtxt, SyntaxEnv, Decorator, ItemDecorator, Modifier, Annotatable};
use ext::base::{ExtCtxt, SyntaxEnv, MultiDecorator, MultiItemDecorator, MultiModifier, Annotatable};
use ext::build::AstBuilder;
use feature_gate;
use codemap::Span;
use parse::token::{intern, intern_and_get_ident};
use ptr::P;
macro_rules! pathvec {
($($x:ident)::+) => (
@ -80,41 +79,46 @@ pub mod generic;
fn expand_derive(cx: &mut ExtCtxt,
span: Span,
mitem: &MetaItem,
item: P<Item>)
-> P<Item> {
item.map(|mut item| {
if mitem.value_str().is_some() {
cx.span_err(mitem.span, "unexpected value in `derive`");
}
let traits = mitem.meta_item_list().unwrap_or(&[]);
if traits.is_empty() {
cx.span_warn(mitem.span, "empty trait list in `derive`");
}
for titem in traits.iter().rev() {
let tname = match titem.node {
MetaWord(ref tname) => tname,
_ => {
cx.span_err(titem.span, "malformed `derive` entry");
continue;
}
};
if !(is_builtin_trait(tname) || cx.ecfg.enable_custom_derive()) {
feature_gate::emit_feature_err(&cx.parse_sess.span_diagnostic,
"custom_derive",
titem.span,
feature_gate::EXPLAIN_CUSTOM_DERIVE);
continue;
annotatable: Annotatable)
-> Annotatable {
annotatable.map_item_or(|item| {
item.map(|mut item| {
if mitem.value_str().is_some() {
cx.span_err(mitem.span, "unexpected value in `derive`");
}
// #[derive(Foo, Bar)] expands to #[derive_Foo] #[derive_Bar]
item.attrs.push(cx.attribute(titem.span, cx.meta_word(titem.span,
intern_and_get_ident(&format!("derive_{}", tname)))));
}
let traits = mitem.meta_item_list().unwrap_or(&[]);
if traits.is_empty() {
cx.span_warn(mitem.span, "empty trait list in `derive`");
}
item
for titem in traits.iter().rev() {
let tname = match titem.node {
MetaWord(ref tname) => tname,
_ => {
cx.span_err(titem.span, "malformed `derive` entry");
continue;
}
};
if !(is_builtin_trait(tname) || cx.ecfg.enable_custom_derive()) {
feature_gate::emit_feature_err(&cx.parse_sess.span_diagnostic,
"custom_derive",
titem.span,
feature_gate::EXPLAIN_CUSTOM_DERIVE);
continue;
}
// #[derive(Foo, Bar)] expands to #[derive_Foo] #[derive_Bar]
item.attrs.push(cx.attribute(titem.span, cx.meta_word(titem.span,
intern_and_get_ident(&format!("derive_{}", tname)))));
}
item
})
}, |a| {
cx.span_err(span, "`derive` can only be applied to items");
a
})
}
@ -125,24 +129,24 @@ macro_rules! derive_traits {
$({
struct DeriveExtension;
impl ItemDecorator for DeriveExtension {
impl MultiItemDecorator for DeriveExtension {
fn expand(&self,
ecx: &mut ExtCtxt,
sp: Span,
mitem: &MetaItem,
item: &Item,
push: &mut FnMut(P<Item>)) {
annotatable: Annotatable,
push: &mut FnMut(Annotatable)) {
warn_if_deprecated(ecx, sp, $name);
$func(ecx, sp, mitem, item, push);
$func(ecx, sp, mitem, annotatable, push);
}
}
env.insert(intern(concat!("derive_", $name)),
Decorator(Box::new(DeriveExtension)));
MultiDecorator(Box::new(DeriveExtension)));
})+
env.insert(intern("derive"),
Modifier(Box::new(expand_derive)));
MultiModifier(Box::new(expand_derive)));
}
fn is_builtin_trait(name: &str) -> bool {

View file

@ -8,10 +8,10 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use ast::{MetaItem, Item, Expr};
use ast::{MetaItem, Expr};
use ast;
use codemap::Span;
use ext::base::ExtCtxt;
use ext::base::{ExtCtxt, Annotatable};
use ext::build::AstBuilder;
use ext::deriving::generic::*;
use ext::deriving::generic::ty::*;
@ -21,8 +21,8 @@ use ptr::P;
pub fn expand_deriving_from_primitive(cx: &mut ExtCtxt,
span: Span,
mitem: &MetaItem,
item: &Item,
push: &mut FnMut(P<Item>))
item: Annotatable,
push: &mut FnMut(Annotatable))
{
let inline = cx.meta_word(span, InternedString::new("inline"));
let attrs = vec!(cx.attribute(span, inline));

View file

@ -9,9 +9,9 @@
// except according to those terms.
use ast;
use ast::{MetaItem, Item, Expr,};
use ast::{MetaItem, Expr,};
use codemap::Span;
use ext::base::ExtCtxt;
use ext::base::{ExtCtxt, Annotatable};
use ext::build::AstBuilder;
use ext::deriving::generic::*;
use ext::deriving::generic::ty::*;
@ -21,8 +21,8 @@ use ptr::P;
pub fn expand_deriving_show(cx: &mut ExtCtxt,
span: Span,
mitem: &MetaItem,
item: &Item,
push: &mut FnMut(P<Item>))
item: Annotatable,
push: &mut FnMut(Annotatable))
{
// &mut ::std::fmt::Formatter
let fmtr = Ptr(Box::new(Literal(path_std!(cx, core::fmt::Formatter))),

View file

@ -477,59 +477,6 @@ pub fn expand_item(it: P<ast::Item>, fld: &mut MacroExpander)
.into_iter().map(|i| i.expect_item()).collect()
}
#[allow(deprecated)] // This is needed because the `ItemModifier` trait is used
fn expand_item_modifiers(mut it: P<ast::Item>, fld: &mut MacroExpander)
-> P<ast::Item> {
// partition the attributes into ItemModifiers and others
let (modifiers, other_attrs) = modifiers(&it.attrs, fld);
// update the attrs, leave everything else alone. Is this mutation really a good idea?
it = P(ast::Item {
attrs: other_attrs,
..(*it).clone()
});
if modifiers.is_empty() {
let it = expand_item_multi_modifier(Annotatable::Item(it), fld);
return it.expect_item();
}
for attr in &modifiers {
let mname = attr.name();
match fld.cx.syntax_env.find(&intern(&mname)) {
Some(rc) => match *rc {
Modifier(ref mac) => {
attr::mark_used(attr);
fld.cx.bt_push(ExpnInfo {
call_site: attr.span,
callee: NameAndSpan {
name: mname.to_string(),
format: MacroAttribute,
span: None,
// attributes can do whatever they like,
// for now
allow_internal_unstable: true,
}
});
it = mac.expand(fld.cx, attr.span, &*attr.node.value, it);
fld.cx.bt_pop();
}
_ => unreachable!()
},
_ => unreachable!()
}
}
// Expansion may have added new ItemModifiers.
// It is possible, that an item modifier could expand to a multi-modifier or
// vice versa. In this case we will expand all modifiers before multi-modifiers,
// which might give an odd ordering. However, I think it is unlikely that the
// two kinds will be mixed, and I old-style multi-modifiers should be deprecated
// anyway.
expand_item_modifiers(it, fld)
}
/// Expand item_underscore
fn expand_item_underscore(item: ast::Item_, fld: &mut MacroExpander) -> ast::Item_ {
match item {
@ -1083,7 +1030,6 @@ impl<'a> Folder for PatIdentRenamer<'a> {
}
}
#[allow(deprecated)] // This is needed because the `Decorator` variant is used
fn expand_annotatable(a: Annotatable,
fld: &mut MacroExpander)
-> SmallVector<Annotatable> {
@ -1091,73 +1037,7 @@ fn expand_annotatable(a: Annotatable,
let mut decorator_items = SmallVector::zero();
let mut new_attrs = Vec::new();
for attr in a.attrs() {
let mname = attr.name();
match fld.cx.syntax_env.find(&intern(&mname)) {
Some(rc) => match *rc {
Decorator(ref dec) => {
let it = match a {
Annotatable::Item(ref it) => it,
// ItemDecorators are only implemented for Items.
_ => break,
};
attr::mark_used(attr);
fld.cx.bt_push(ExpnInfo {
call_site: attr.span,
callee: NameAndSpan {
name: mname.to_string(),
format: MacroAttribute,
span: Some(attr.span),
// attributes can do whatever they like,
// for now.
allow_internal_unstable: true,
}
});
// we'd ideally decorator_items.push_all(expand_item(item, fld)),
// but that double-mut-borrows fld
let mut items: SmallVector<P<ast::Item>> = SmallVector::zero();
dec.expand(fld.cx, attr.span, &*attr.node.value, &**it,
&mut |item| items.push(item));
decorator_items.extend(items.into_iter()
.flat_map(|item| expand_item(item, fld).into_iter()
.map(|i| Annotatable::Item(i))));
fld.cx.bt_pop();
}
MultiDecorator(ref dec) => {
attr::mark_used(attr);
fld.cx.bt_push(ExpnInfo {
call_site: attr.span,
callee: NameAndSpan {
name: mname.to_string(),
format: MacroAttribute,
span: Some(attr.span),
// attributes can do whatever they like,
// for now.
allow_internal_unstable: true,
}
});
// we'd ideally decorator_items.push_all(expand_annotatable(ann, fld)),
// but that double-mut-borrows fld
let mut anns: SmallVector<Annotatable> = SmallVector::zero();
dec.expand(fld.cx, attr.span, &*attr.node.value, &a,
&mut |ann| anns.push(ann));
decorator_items.extend(anns.into_iter()
.flat_map(|ann| expand_annotatable(ann, fld).into_iter()));
fld.cx.bt_pop();
}
_ => new_attrs.push((*attr).clone()),
},
_ => new_attrs.push((*attr).clone()),
}
}
expand_decorators(a.clone(), fld, &mut decorator_items, &mut new_attrs);
let mut new_items: SmallVector<Annotatable> = match a {
Annotatable::Item(it) => match it.node {
@ -1215,34 +1095,101 @@ fn expand_annotatable(a: Annotatable,
new_items
}
// partition the attributes into ItemModifiers and others
fn modifiers(attrs: &Vec<ast::Attribute>,
fld: &MacroExpander)
-> (Vec<ast::Attribute>, Vec<ast::Attribute>) {
attrs.iter().cloned().partition(|attr| {
match fld.cx.syntax_env.find(&intern(&attr.name())) {
Some(rc) => match *rc {
Modifier(_) => true,
_ => false
},
_ => false
// Partition a set of attributes into one kind of attribute, and other kinds.
macro_rules! partition {
($fn_name: ident, $variant: ident) => {
#[allow(deprecated)] // The `allow` is needed because the `Modifier` variant might be used.
fn $fn_name(attrs: &[ast::Attribute],
fld: &MacroExpander)
-> (Vec<ast::Attribute>, Vec<ast::Attribute>) {
attrs.iter().cloned().partition(|attr| {
match fld.cx.syntax_env.find(&intern(&attr.name())) {
Some(rc) => match *rc {
$variant(..) => true,
_ => false
},
_ => false
}
})
}
})
}
}
// partition the attributes into MultiModifiers and others
fn multi_modifiers(attrs: &[ast::Attribute],
fld: &MacroExpander)
-> (Vec<ast::Attribute>, Vec<ast::Attribute>) {
attrs.iter().cloned().partition(|attr| {
match fld.cx.syntax_env.find(&intern(&attr.name())) {
partition!(modifiers, Modifier);
partition!(multi_modifiers, MultiModifier);
#[allow(deprecated)] // The `allow` is needed because the `Decorator` variant is used.
fn expand_decorators(a: Annotatable,
fld: &mut MacroExpander,
decorator_items: &mut SmallVector<Annotatable>,
new_attrs: &mut Vec<ast::Attribute>)
{
for attr in a.attrs() {
let mname = attr.name();
match fld.cx.syntax_env.find(&intern(&mname)) {
Some(rc) => match *rc {
MultiModifier(_) => true,
_ => false
Decorator(ref dec) => {
attr::mark_used(&attr);
fld.cx.bt_push(ExpnInfo {
call_site: attr.span,
callee: NameAndSpan {
name: mname.to_string(),
format: MacroAttribute,
span: Some(attr.span),
// attributes can do whatever they like,
// for now.
allow_internal_unstable: true,
}
});
// we'd ideally decorator_items.push_all(expand_item(item, fld)),
// but that double-mut-borrows fld
let mut items: SmallVector<Annotatable> = SmallVector::zero();
dec.expand(fld.cx,
attr.span,
&attr.node.value,
&a.clone().expect_item(),
&mut |item| items.push(Annotatable::Item(item)));
decorator_items.extend(items.into_iter()
.flat_map(|ann| expand_annotatable(ann, fld).into_iter()));
fld.cx.bt_pop();
}
MultiDecorator(ref dec) => {
attr::mark_used(&attr);
fld.cx.bt_push(ExpnInfo {
call_site: attr.span,
callee: NameAndSpan {
name: mname.to_string(),
format: MacroAttribute,
span: Some(attr.span),
// attributes can do whatever they like,
// for now.
allow_internal_unstable: true,
}
});
// we'd ideally decorator_items.push_all(expand_annotatable(ann, fld)),
// but that double-mut-borrows fld
let mut items: SmallVector<Annotatable> = SmallVector::zero();
dec.expand(fld.cx,
attr.span,
&attr.node.value,
a.clone(),
&mut |ann| items.push(ann));
decorator_items.extend(items.into_iter()
.flat_map(|ann| expand_annotatable(ann, fld).into_iter()));
fld.cx.bt_pop();
}
_ => new_attrs.push((*attr).clone()),
},
_ => false
_ => new_attrs.push((*attr).clone()),
}
})
}
}
fn expand_item_multi_modifier(mut it: Annotatable,
@ -1269,7 +1216,7 @@ fn expand_item_multi_modifier(mut it: Annotatable,
callee: NameAndSpan {
name: mname.to_string(),
format: MacroAttribute,
span: None,
span: Some(attr.span),
// attributes can do whatever they like,
// for now
allow_internal_unstable: true,
@ -1288,6 +1235,59 @@ fn expand_item_multi_modifier(mut it: Annotatable,
expand_item_multi_modifier(it, fld)
}
#[allow(deprecated)] // This is needed because the `ItemModifier` trait is used
fn expand_item_modifiers(mut it: P<ast::Item>,
fld: &mut MacroExpander)
-> P<ast::Item> {
// partition the attributes into ItemModifiers and others
let (modifiers, other_attrs) = modifiers(&it.attrs, fld);
// update the attrs, leave everything else alone. Is this mutation really a good idea?
it = P(ast::Item {
attrs: other_attrs,
..(*it).clone()
});
if modifiers.is_empty() {
let it = expand_item_multi_modifier(Annotatable::Item(it), fld);
return it.expect_item();
}
for attr in &modifiers {
let mname = attr.name();
match fld.cx.syntax_env.find(&intern(&mname)) {
Some(rc) => match *rc {
Modifier(ref mac) => {
attr::mark_used(attr);
fld.cx.bt_push(ExpnInfo {
call_site: attr.span,
callee: NameAndSpan {
name: mname.to_string(),
format: MacroAttribute,
span: Some(attr.span),
// attributes can do whatever they like,
// for now
allow_internal_unstable: true,
}
});
it = mac.expand(fld.cx, attr.span, &*attr.node.value, it);
fld.cx.bt_pop();
}
_ => unreachable!()
},
_ => unreachable!()
}
}
// Expansion may have added new ItemModifiers.
// It is possible, that an item modifier could expand to a multi-modifier or
// vice versa. In this case we will expand all modifiers before multi-modifiers,
// which might give an odd ordering. However, I think it is unlikely that the
// two kinds will be mixed, and old-style multi-modifiers are deprecated.
expand_item_modifiers(it, fld)
}
fn expand_impl_item(ii: P<ast::ImplItem>, fld: &mut MacroExpander)
-> SmallVector<P<ast::ImplItem>> {
match ii.node {