mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-10 14:57:14 +00:00
auto merge of #21052 : nick29581/rust/methods-ext, r=sfackler
Allows modifiers to be used on methods, associated types, etc. r? @sfackler
This commit is contained in:
commit
8903c21d61
@ -14,7 +14,7 @@ use lint::{LintPassObject, LintId, Lint};
|
|||||||
use session::Session;
|
use session::Session;
|
||||||
|
|
||||||
use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension, NormalTT};
|
use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension, NormalTT};
|
||||||
use syntax::ext::base::{IdentTT, Decorator, Modifier, MacroRulesTT};
|
use syntax::ext::base::{IdentTT, Decorator, Modifier, MultiModifier, MacroRulesTT};
|
||||||
use syntax::ext::base::{MacroExpanderFn};
|
use syntax::ext::base::{MacroExpanderFn};
|
||||||
use syntax::codemap::Span;
|
use syntax::codemap::Span;
|
||||||
use syntax::parse::token;
|
use syntax::parse::token;
|
||||||
@ -82,7 +82,7 @@ impl<'a> Registry<'a> {
|
|||||||
IdentTT(ext, _) => IdentTT(ext, Some(self.krate_span)),
|
IdentTT(ext, _) => IdentTT(ext, Some(self.krate_span)),
|
||||||
Decorator(ext) => Decorator(ext),
|
Decorator(ext) => Decorator(ext),
|
||||||
Modifier(ext) => Modifier(ext),
|
Modifier(ext) => Modifier(ext),
|
||||||
|
MultiModifier(ext) => MultiModifier(ext),
|
||||||
MacroRulesTT => {
|
MacroRulesTT => {
|
||||||
self.sess.err("plugin tried to register a new MacroRulesTT");
|
self.sess.err("plugin tried to register a new MacroRulesTT");
|
||||||
return;
|
return;
|
||||||
|
@ -73,6 +73,108 @@ impl<F> ItemModifier for F
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Show,Clone)]
|
||||||
|
pub enum Annotatable {
|
||||||
|
Item(P<ast::Item>),
|
||||||
|
TraitItem(ast::TraitItem),
|
||||||
|
ImplItem(ast::ImplItem),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Annotatable {
|
||||||
|
pub fn attrs(&self) -> &[ast::Attribute] {
|
||||||
|
match *self {
|
||||||
|
Annotatable::Item(ref i) => &i.attrs[],
|
||||||
|
Annotatable::TraitItem(ref i) => match *i {
|
||||||
|
ast::TraitItem::RequiredMethod(ref tm) => &tm.attrs[],
|
||||||
|
ast::TraitItem::ProvidedMethod(ref m) => &m.attrs[],
|
||||||
|
ast::TraitItem::TypeTraitItem(ref at) => &at.attrs[],
|
||||||
|
},
|
||||||
|
Annotatable::ImplItem(ref i) => match *i {
|
||||||
|
ast::ImplItem::MethodImplItem(ref m) => &m.attrs[],
|
||||||
|
ast::ImplItem::TypeImplItem(ref t) => &t.attrs[],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fold_attrs(self, attrs: Vec<ast::Attribute>) -> Annotatable {
|
||||||
|
match self {
|
||||||
|
Annotatable::Item(i) => Annotatable::Item(P(ast::Item {
|
||||||
|
attrs: attrs,
|
||||||
|
..(*i).clone()
|
||||||
|
})),
|
||||||
|
Annotatable::TraitItem(i) => match i {
|
||||||
|
ast::TraitItem::RequiredMethod(tm) => Annotatable::TraitItem(
|
||||||
|
ast::TraitItem::RequiredMethod(
|
||||||
|
ast::TypeMethod { attrs: attrs, ..tm })),
|
||||||
|
ast::TraitItem::ProvidedMethod(m) => Annotatable::TraitItem(
|
||||||
|
ast::TraitItem::ProvidedMethod(P(
|
||||||
|
ast::Method { attrs: attrs, ..(*m).clone() }))),
|
||||||
|
ast::TraitItem::TypeTraitItem(at) => Annotatable::TraitItem(
|
||||||
|
ast::TraitItem::TypeTraitItem(P(
|
||||||
|
ast::AssociatedType { attrs: attrs, ..(*at).clone() }))),
|
||||||
|
},
|
||||||
|
Annotatable::ImplItem(i) => match i {
|
||||||
|
ast::ImplItem::MethodImplItem(m) => Annotatable::ImplItem(
|
||||||
|
ast::ImplItem::MethodImplItem(P(
|
||||||
|
ast::Method { attrs: attrs, ..(*m).clone() }))),
|
||||||
|
ast::ImplItem::TypeImplItem(t) => Annotatable::ImplItem(
|
||||||
|
ast::ImplItem::TypeImplItem(P(
|
||||||
|
ast::Typedef { attrs: attrs, ..(*t).clone() }))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn expect_item(self) -> P<ast::Item> {
|
||||||
|
match self {
|
||||||
|
Annotatable::Item(i) => i,
|
||||||
|
_ => panic!("expected Item")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn expect_trait_item(self) -> ast::TraitItem {
|
||||||
|
match self {
|
||||||
|
Annotatable::TraitItem(i) => i,
|
||||||
|
_ => panic!("expected Item")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn expect_impl_item(self) -> ast::ImplItem {
|
||||||
|
match self {
|
||||||
|
Annotatable::ImplItem(i) => i,
|
||||||
|
_ => panic!("expected Item")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A more flexible ItemModifier (ItemModifier should go away, eventually, FIXME).
|
||||||
|
// meta_item is the annotation, item is the item being modified, parent_item
|
||||||
|
// is the impl or trait item is declared in if item is part of such a thing.
|
||||||
|
// FIXME Decorators should follow the same pattern too.
|
||||||
|
pub trait MultiItemModifier {
|
||||||
|
fn expand(&self,
|
||||||
|
ecx: &mut ExtCtxt,
|
||||||
|
span: Span,
|
||||||
|
meta_item: &ast::MetaItem,
|
||||||
|
item: Annotatable)
|
||||||
|
-> Annotatable;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F> MultiItemModifier for F
|
||||||
|
where F: Fn(&mut ExtCtxt,
|
||||||
|
Span,
|
||||||
|
&ast::MetaItem,
|
||||||
|
Annotatable) -> Annotatable
|
||||||
|
{
|
||||||
|
fn expand(&self,
|
||||||
|
ecx: &mut ExtCtxt,
|
||||||
|
span: Span,
|
||||||
|
meta_item: &ast::MetaItem,
|
||||||
|
item: Annotatable)
|
||||||
|
-> Annotatable {
|
||||||
|
(*self)(ecx, span, meta_item, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Represents a thing that maps token trees to Macro Results
|
/// Represents a thing that maps token trees to Macro Results
|
||||||
pub trait TTMacroExpander {
|
pub trait TTMacroExpander {
|
||||||
fn expand<'cx>(&self,
|
fn expand<'cx>(&self,
|
||||||
@ -299,6 +401,10 @@ pub enum SyntaxExtension {
|
|||||||
/// in-place.
|
/// in-place.
|
||||||
Modifier(Box<ItemModifier + 'static>),
|
Modifier(Box<ItemModifier + 'static>),
|
||||||
|
|
||||||
|
/// A syntax extension that is attached to an item and modifies it
|
||||||
|
/// in-place. More flexible version than Modifier.
|
||||||
|
MultiModifier(Box<MultiItemModifier + 'static>),
|
||||||
|
|
||||||
/// A normal, function-like syntax extension.
|
/// A normal, function-like syntax extension.
|
||||||
///
|
///
|
||||||
/// `bytes!` is a `NormalTT`.
|
/// `bytes!` is a `NormalTT`.
|
||||||
|
@ -395,81 +395,15 @@ pub fn expand_item(it: P<ast::Item>, fld: &mut MacroExpander)
|
|||||||
-> SmallVector<P<ast::Item>> {
|
-> SmallVector<P<ast::Item>> {
|
||||||
let it = expand_item_modifiers(it, fld);
|
let it = expand_item_modifiers(it, fld);
|
||||||
|
|
||||||
let mut decorator_items = SmallVector::zero();
|
expand_annotatable(Annotatable::Item(it), fld)
|
||||||
let mut new_attrs = Vec::new();
|
.into_iter().map(|i| i.expect_item()).collect()
|
||||||
for attr in it.attrs.iter() {
|
|
||||||
let mname = attr.name();
|
|
||||||
|
|
||||||
match fld.cx.syntax_env.find(&intern(mname.get())) {
|
|
||||||
Some(rc) => match *rc {
|
|
||||||
Decorator(ref dec) => {
|
|
||||||
attr::mark_used(attr);
|
|
||||||
|
|
||||||
fld.cx.bt_push(ExpnInfo {
|
|
||||||
call_site: attr.span,
|
|
||||||
callee: NameAndSpan {
|
|
||||||
name: mname.get().to_string(),
|
|
||||||
format: MacroAttribute,
|
|
||||||
span: None
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 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,
|
|
||||||
box |&mut : item| items.push(item));
|
|
||||||
decorator_items.extend(items.into_iter()
|
|
||||||
.flat_map(|item| expand_item(item, fld).into_iter()));
|
|
||||||
|
|
||||||
fld.cx.bt_pop();
|
|
||||||
}
|
|
||||||
_ => new_attrs.push((*attr).clone()),
|
|
||||||
},
|
|
||||||
_ => new_attrs.push((*attr).clone()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut new_items = match it.node {
|
|
||||||
ast::ItemMac(..) => expand_item_mac(it, fld),
|
|
||||||
ast::ItemMod(_) | ast::ItemForeignMod(_) => {
|
|
||||||
let valid_ident =
|
|
||||||
it.ident.name != parse::token::special_idents::invalid.name;
|
|
||||||
|
|
||||||
if valid_ident {
|
|
||||||
fld.cx.mod_push(it.ident);
|
|
||||||
}
|
|
||||||
let macro_use = contains_macro_use(fld, &new_attrs[]);
|
|
||||||
let result = with_exts_frame!(fld.cx.syntax_env,
|
|
||||||
macro_use,
|
|
||||||
noop_fold_item(it, fld));
|
|
||||||
if valid_ident {
|
|
||||||
fld.cx.mod_pop();
|
|
||||||
}
|
|
||||||
result
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
let it = P(ast::Item {
|
|
||||||
attrs: new_attrs,
|
|
||||||
..(*it).clone()
|
|
||||||
});
|
|
||||||
noop_fold_item(it, fld)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
new_items.push_all(decorator_items);
|
|
||||||
new_items
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expand_item_modifiers(mut it: P<ast::Item>, fld: &mut MacroExpander)
|
fn expand_item_modifiers(mut it: P<ast::Item>, fld: &mut MacroExpander)
|
||||||
-> P<ast::Item> {
|
-> P<ast::Item> {
|
||||||
// partition the attributes into ItemModifiers and others
|
// partition the attributes into ItemModifiers and others
|
||||||
let (modifiers, other_attrs): (Vec<_>, _) = it.attrs.iter().cloned().partition(|attr| {
|
let (modifiers, other_attrs) = modifiers(&it.attrs, fld);
|
||||||
match fld.cx.syntax_env.find(&intern(attr.name().get())) {
|
|
||||||
Some(rc) => match *rc { Modifier(_) => true, _ => false },
|
|
||||||
_ => false
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// update the attrs, leave everything else alone. Is this mutation really a good idea?
|
// update the attrs, leave everything else alone. Is this mutation really a good idea?
|
||||||
it = P(ast::Item {
|
it = P(ast::Item {
|
||||||
attrs: other_attrs,
|
attrs: other_attrs,
|
||||||
@ -477,7 +411,8 @@ fn expand_item_modifiers(mut it: P<ast::Item>, fld: &mut MacroExpander)
|
|||||||
});
|
});
|
||||||
|
|
||||||
if modifiers.is_empty() {
|
if modifiers.is_empty() {
|
||||||
return it;
|
let it = expand_item_multi_modifier(Annotatable::Item(it), fld);
|
||||||
|
return it.expect_item();
|
||||||
}
|
}
|
||||||
|
|
||||||
for attr in modifiers.iter() {
|
for attr in modifiers.iter() {
|
||||||
@ -504,7 +439,12 @@ fn expand_item_modifiers(mut it: P<ast::Item>, fld: &mut MacroExpander)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// expansion may have added new ItemModifiers
|
// 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_modifiers(it, fld)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1029,6 +969,196 @@ impl<'a> Folder for PatIdentRenamer<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn expand_annotatable(a: Annotatable,
|
||||||
|
fld: &mut MacroExpander)
|
||||||
|
-> SmallVector<Annotatable> {
|
||||||
|
let a = expand_item_multi_modifier(a, fld);
|
||||||
|
|
||||||
|
let mut decorator_items = SmallVector::zero();
|
||||||
|
let mut new_attrs = Vec::new();
|
||||||
|
for attr in a.attrs().iter() {
|
||||||
|
let mname = attr.name();
|
||||||
|
|
||||||
|
match fld.cx.syntax_env.find(&intern(mname.get())) {
|
||||||
|
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.get().to_string(),
|
||||||
|
format: MacroAttribute,
|
||||||
|
span: None
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 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,
|
||||||
|
box |&mut: item| items.push(item));
|
||||||
|
decorator_items.extend(items.into_iter()
|
||||||
|
.flat_map(|item| expand_item(item, fld).into_iter()));
|
||||||
|
|
||||||
|
fld.cx.bt_pop();
|
||||||
|
}
|
||||||
|
_ => new_attrs.push((*attr).clone()),
|
||||||
|
},
|
||||||
|
_ => new_attrs.push((*attr).clone()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut new_items: SmallVector<Annotatable> = match a {
|
||||||
|
Annotatable::Item(it) => match it.node {
|
||||||
|
ast::ItemMac(..) => {
|
||||||
|
expand_item_mac(it, fld).into_iter().map(|i| Annotatable::Item(i)).collect()
|
||||||
|
}
|
||||||
|
ast::ItemMod(_) | ast::ItemForeignMod(_) => {
|
||||||
|
let valid_ident =
|
||||||
|
it.ident.name != parse::token::special_idents::invalid.name;
|
||||||
|
|
||||||
|
if valid_ident {
|
||||||
|
fld.cx.mod_push(it.ident);
|
||||||
|
}
|
||||||
|
let macro_use = contains_macro_use(fld, &new_attrs[]);
|
||||||
|
let result = with_exts_frame!(fld.cx.syntax_env,
|
||||||
|
macro_use,
|
||||||
|
noop_fold_item(it, fld));
|
||||||
|
if valid_ident {
|
||||||
|
fld.cx.mod_pop();
|
||||||
|
}
|
||||||
|
result.into_iter().map(|i| Annotatable::Item(i)).collect()
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
let it = P(ast::Item {
|
||||||
|
attrs: new_attrs,
|
||||||
|
..(*it).clone()
|
||||||
|
});
|
||||||
|
noop_fold_item(it, fld).into_iter().map(|i| Annotatable::Item(i)).collect()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Annotatable::TraitItem(it) => match it {
|
||||||
|
ast::TraitItem::ProvidedMethod(m) => {
|
||||||
|
expand_method(m, fld).into_iter().map(|m|
|
||||||
|
Annotatable::TraitItem(ast::TraitItem::ProvidedMethod(m))).collect()
|
||||||
|
}
|
||||||
|
ast::TraitItem::RequiredMethod(m) => {
|
||||||
|
SmallVector::one(Annotatable::TraitItem(
|
||||||
|
ast::TraitItem::RequiredMethod(fld.fold_type_method(m))))
|
||||||
|
}
|
||||||
|
ast::TraitItem::TypeTraitItem(t) => {
|
||||||
|
SmallVector::one(Annotatable::TraitItem(
|
||||||
|
ast::TraitItem::TypeTraitItem(P(fld.fold_associated_type((*t).clone())))))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Annotatable::ImplItem(it) => match it {
|
||||||
|
ast::ImplItem::MethodImplItem(m) => {
|
||||||
|
expand_method(m, fld).into_iter().map(|m|
|
||||||
|
Annotatable::ImplItem(ast::ImplItem::MethodImplItem(m))).collect()
|
||||||
|
}
|
||||||
|
ast::ImplItem::TypeImplItem(t) => {
|
||||||
|
SmallVector::one(Annotatable::ImplItem(
|
||||||
|
ast::ImplItem::TypeImplItem(P(fld.fold_typedef((*t).clone())))))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
new_items.push_all(decorator_items.into_iter().map(|i| Annotatable::Item(i)).collect());
|
||||||
|
new_items
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expand_trait_item(i: ast::TraitItem,
|
||||||
|
fld: &mut MacroExpander)
|
||||||
|
-> SmallVector<ast::TraitItem> {
|
||||||
|
expand_annotatable(Annotatable::TraitItem(i), fld)
|
||||||
|
.into_iter().map(|i| i.expect_trait_item()).collect()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expand_impl_item(i: ast::ImplItem,
|
||||||
|
fld: &mut MacroExpander)
|
||||||
|
-> SmallVector<ast::ImplItem> {
|
||||||
|
expand_annotatable(Annotatable::ImplItem(i), fld)
|
||||||
|
.into_iter().map(|i| i.expect_impl_item()).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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().get())) {
|
||||||
|
Some(rc) => match *rc {
|
||||||
|
Modifier(_) => 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().get())) {
|
||||||
|
Some(rc) => match *rc {
|
||||||
|
MultiModifier(_) => true,
|
||||||
|
_ => false
|
||||||
|
},
|
||||||
|
_ => false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expand_item_multi_modifier(mut it: Annotatable,
|
||||||
|
fld: &mut MacroExpander)
|
||||||
|
-> Annotatable {
|
||||||
|
let (modifiers, other_attrs) = multi_modifiers(it.attrs(), fld);
|
||||||
|
|
||||||
|
// Update the attrs, leave everything else alone. Is this mutation really a good idea?
|
||||||
|
it = it.fold_attrs(other_attrs);
|
||||||
|
|
||||||
|
if modifiers.is_empty() {
|
||||||
|
return it
|
||||||
|
}
|
||||||
|
|
||||||
|
for attr in modifiers.iter() {
|
||||||
|
let mname = attr.name();
|
||||||
|
|
||||||
|
match fld.cx.syntax_env.find(&intern(mname.get())) {
|
||||||
|
Some(rc) => match *rc {
|
||||||
|
MultiModifier(ref mac) => {
|
||||||
|
attr::mark_used(attr);
|
||||||
|
fld.cx.bt_push(ExpnInfo {
|
||||||
|
call_site: attr.span,
|
||||||
|
callee: NameAndSpan {
|
||||||
|
name: mname.get().to_string(),
|
||||||
|
format: MacroAttribute,
|
||||||
|
span: None,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
it = mac.expand(fld.cx, attr.span, &*attr.node.value, it);
|
||||||
|
fld.cx.bt_pop();
|
||||||
|
}
|
||||||
|
_ => unreachable!()
|
||||||
|
},
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expansion may have added new ItemModifiers.
|
||||||
|
expand_item_multi_modifier(it, fld)
|
||||||
|
}
|
||||||
|
|
||||||
// expand a method
|
// expand a method
|
||||||
fn expand_method(m: P<ast::Method>, fld: &mut MacroExpander) -> SmallVector<P<ast::Method>> {
|
fn expand_method(m: P<ast::Method>, fld: &mut MacroExpander) -> SmallVector<P<ast::Method>> {
|
||||||
m.and_then(|m| match m.node {
|
m.and_then(|m| match m.node {
|
||||||
@ -1147,6 +1277,14 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
|
|||||||
expand_arm(arm, self)
|
expand_arm(arm, self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fold_trait_item(&mut self, i: ast::TraitItem) -> SmallVector<ast::TraitItem> {
|
||||||
|
expand_trait_item(i, self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fold_impl_item(&mut self, i: ast::ImplItem) -> SmallVector<ast::ImplItem> {
|
||||||
|
expand_impl_item(i, self)
|
||||||
|
}
|
||||||
|
|
||||||
fn fold_method(&mut self, method: P<ast::Method>) -> SmallVector<P<ast::Method>> {
|
fn fold_method(&mut self, method: P<ast::Method>) -> SmallVector<P<ast::Method>> {
|
||||||
expand_method(method, self)
|
expand_method(method, self)
|
||||||
}
|
}
|
||||||
|
@ -102,6 +102,14 @@ pub trait Folder : Sized {
|
|||||||
noop_fold_item_underscore(i, self)
|
noop_fold_item_underscore(i, self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fold_trait_item(&mut self, i: TraitItem) -> SmallVector<TraitItem> {
|
||||||
|
noop_fold_trait_item(i, self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fold_impl_item(&mut self, i: ImplItem) -> SmallVector<ImplItem> {
|
||||||
|
noop_fold_impl_item(i, self)
|
||||||
|
}
|
||||||
|
|
||||||
fn fold_fn_decl(&mut self, d: P<FnDecl>) -> P<FnDecl> {
|
fn fold_fn_decl(&mut self, d: P<FnDecl>) -> P<FnDecl> {
|
||||||
noop_fold_fn_decl(d, self)
|
noop_fold_fn_decl(d, self)
|
||||||
}
|
}
|
||||||
@ -1007,21 +1015,9 @@ pub fn noop_fold_item_underscore<T: Folder>(i: Item_, folder: &mut T) -> Item_ {
|
|||||||
ItemStruct(struct_def, folder.fold_generics(generics))
|
ItemStruct(struct_def, folder.fold_generics(generics))
|
||||||
}
|
}
|
||||||
ItemImpl(unsafety, polarity, generics, ifce, ty, impl_items) => {
|
ItemImpl(unsafety, polarity, generics, ifce, ty, impl_items) => {
|
||||||
let mut new_impl_items = Vec::new();
|
let new_impl_items = impl_items.into_iter().flat_map(|item| {
|
||||||
for impl_item in impl_items.iter() {
|
folder.fold_impl_item(item).into_iter()
|
||||||
match *impl_item {
|
}).collect();
|
||||||
MethodImplItem(ref x) => {
|
|
||||||
for method in folder.fold_method((*x).clone())
|
|
||||||
.into_iter() {
|
|
||||||
new_impl_items.push(MethodImplItem(method))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TypeImplItem(ref t) => {
|
|
||||||
new_impl_items.push(TypeImplItem(
|
|
||||||
P(folder.fold_typedef((**t).clone()))));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let ifce = match ifce {
|
let ifce = match ifce {
|
||||||
None => None,
|
None => None,
|
||||||
Some(ref trait_ref) => {
|
Some(ref trait_ref) => {
|
||||||
@ -1035,40 +1031,47 @@ pub fn noop_fold_item_underscore<T: Folder>(i: Item_, folder: &mut T) -> Item_ {
|
|||||||
folder.fold_ty(ty),
|
folder.fold_ty(ty),
|
||||||
new_impl_items)
|
new_impl_items)
|
||||||
}
|
}
|
||||||
ItemTrait(unsafety, generics, bounds, methods) => {
|
ItemTrait(unsafety, generics, bounds, items) => {
|
||||||
let bounds = folder.fold_bounds(bounds);
|
let bounds = folder.fold_bounds(bounds);
|
||||||
let methods = methods.into_iter().flat_map(|method| {
|
let items = items.into_iter().flat_map(|item| {
|
||||||
let r = match method {
|
folder.fold_trait_item(item).into_iter()
|
||||||
|
}).collect();
|
||||||
|
ItemTrait(unsafety,
|
||||||
|
folder.fold_generics(generics),
|
||||||
|
bounds,
|
||||||
|
items)
|
||||||
|
}
|
||||||
|
ItemMac(m) => ItemMac(folder.fold_mac(m)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn noop_fold_trait_item<T: Folder>(i: TraitItem, folder: &mut T) -> SmallVector<TraitItem> {
|
||||||
|
match i {
|
||||||
RequiredMethod(m) => {
|
RequiredMethod(m) => {
|
||||||
SmallVector::one(RequiredMethod(
|
SmallVector::one(RequiredMethod(
|
||||||
folder.fold_type_method(m)))
|
folder.fold_type_method(m)))
|
||||||
.into_iter()
|
|
||||||
}
|
}
|
||||||
ProvidedMethod(method) => {
|
ProvidedMethod(method) => {
|
||||||
// the awkward collect/iter idiom here is because
|
|
||||||
// even though an iter and a map satisfy the same
|
|
||||||
// trait bound, they're not actually the same type, so
|
|
||||||
// the method arms don't unify.
|
|
||||||
let methods: SmallVector<ast::TraitItem> =
|
|
||||||
folder.fold_method(method).into_iter()
|
folder.fold_method(method).into_iter()
|
||||||
.map(|m| ProvidedMethod(m)).collect();
|
.map(|m| ProvidedMethod(m)).collect()
|
||||||
methods.into_iter()
|
|
||||||
}
|
}
|
||||||
TypeTraitItem(at) => {
|
TypeTraitItem(at) => {
|
||||||
SmallVector::one(TypeTraitItem(P(
|
SmallVector::one(TypeTraitItem(P(
|
||||||
folder.fold_associated_type(
|
folder.fold_associated_type(
|
||||||
(*at).clone()))))
|
(*at).clone()))))
|
||||||
.into_iter()
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
r
|
|
||||||
}).collect();
|
|
||||||
ItemTrait(unsafety,
|
|
||||||
folder.fold_generics(generics),
|
|
||||||
bounds,
|
|
||||||
methods)
|
|
||||||
}
|
}
|
||||||
ItemMac(m) => ItemMac(folder.fold_mac(m)),
|
}
|
||||||
|
|
||||||
|
pub fn noop_fold_impl_item<T: Folder>(i: ImplItem, folder: &mut T) -> SmallVector<ImplItem> {
|
||||||
|
match i {
|
||||||
|
MethodImplItem(ref x) => {
|
||||||
|
folder.fold_method((*x).clone()).into_iter().map(|m| MethodImplItem(m)).collect()
|
||||||
|
}
|
||||||
|
TypeImplItem(ref t) => {
|
||||||
|
SmallVector::one(TypeImplItem(
|
||||||
|
P(folder.fold_typedef((**t).clone()))))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
|
// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT
|
||||||
// file at the top-level directory of this distribution and at
|
// file at the top-level directory of this distribution and at
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
//
|
//
|
||||||
@ -16,7 +16,7 @@
|
|||||||
extern crate syntax;
|
extern crate syntax;
|
||||||
extern crate rustc;
|
extern crate rustc;
|
||||||
|
|
||||||
use syntax::ast::{TokenTree, Item, MetaItem};
|
use syntax::ast::{TokenTree, Item, MetaItem, ImplItem, TraitItem, Method};
|
||||||
use syntax::codemap::Span;
|
use syntax::codemap::Span;
|
||||||
use syntax::ext::base::*;
|
use syntax::ext::base::*;
|
||||||
use syntax::parse::token;
|
use syntax::parse::token;
|
||||||
@ -37,6 +37,9 @@ pub fn plugin_registrar(reg: &mut Registry) {
|
|||||||
reg.register_syntax_extension(
|
reg.register_syntax_extension(
|
||||||
token::intern("into_foo"),
|
token::intern("into_foo"),
|
||||||
Modifier(box expand_into_foo));
|
Modifier(box expand_into_foo));
|
||||||
|
reg.register_syntax_extension(
|
||||||
|
token::intern("into_multi_foo"),
|
||||||
|
MultiModifier(box expand_into_foo_multi));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expand_make_a_1(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree])
|
fn expand_make_a_1(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree])
|
||||||
@ -65,6 +68,30 @@ fn expand_into_foo(cx: &mut ExtCtxt, sp: Span, attr: &MetaItem, it: P<Item>)
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn expand_into_foo_multi(cx: &mut ExtCtxt,
|
||||||
|
sp: Span,
|
||||||
|
attr: &MetaItem,
|
||||||
|
it: Annotatable) -> Annotatable {
|
||||||
|
match it {
|
||||||
|
Annotatable::Item(it) => {
|
||||||
|
Annotatable::Item(P(Item {
|
||||||
|
attrs: it.attrs.clone(),
|
||||||
|
..(*quote_item!(cx, enum Foo2 { Bar2, Baz2 }).unwrap()).clone()
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
Annotatable::ImplItem(it) => {
|
||||||
|
Annotatable::ImplItem(ImplItem::MethodImplItem(
|
||||||
|
quote_method!(cx, fn foo(&self) -> i32 { 42 })
|
||||||
|
))
|
||||||
|
}
|
||||||
|
Annotatable::TraitItem(it) => {
|
||||||
|
Annotatable::TraitItem(TraitItem::ProvidedMethod(
|
||||||
|
quote_method!(cx, fn foo(&self) -> i32 { 0 })
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn expand_forged_ident(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box<MacResult+'static> {
|
fn expand_forged_ident(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box<MacResult+'static> {
|
||||||
use syntax::ext::quote::rt::*;
|
use syntax::ext::quote::rt::*;
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
|
// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT
|
||||||
// file at the top-level directory of this distribution and at
|
// file at the top-level directory of this distribution and at
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
//
|
//
|
||||||
@ -20,12 +20,36 @@ extern crate macro_crate_test;
|
|||||||
#[derive(PartialEq, Clone, Show)]
|
#[derive(PartialEq, Clone, Show)]
|
||||||
fn foo() -> AFakeTypeThatHadBetterGoAway {}
|
fn foo() -> AFakeTypeThatHadBetterGoAway {}
|
||||||
|
|
||||||
|
#[into_multi_foo]
|
||||||
|
#[derive(PartialEq, Clone, Show)]
|
||||||
|
fn foo() -> AnotherFakeTypeThatHadBetterGoAway {}
|
||||||
|
|
||||||
|
trait Qux {
|
||||||
|
#[into_multi_foo]
|
||||||
|
fn bar();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Qux for i32 {
|
||||||
|
#[into_multi_foo]
|
||||||
|
fn bar() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Qux for u8 {}
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
assert_eq!(1, make_a_1!());
|
assert_eq!(1, make_a_1!());
|
||||||
assert_eq!(2, exported_macro!());
|
assert_eq!(2, exported_macro!());
|
||||||
|
|
||||||
assert_eq!(Foo::Bar, Foo::Bar);
|
assert_eq!(Foo::Bar, Foo::Bar);
|
||||||
test(None::<Foo>);
|
test(None::<Foo>);
|
||||||
|
|
||||||
|
assert_eq!(Foo2::Bar2, Foo2::Bar2);
|
||||||
|
test(None::<Foo2>);
|
||||||
|
|
||||||
|
let x = 10i32;
|
||||||
|
assert_eq!(x.foo(), 42);
|
||||||
|
let x = 10u8;
|
||||||
|
assert_eq!(x.foo(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test<T: PartialEq+Clone>(_: Option<T>) {}
|
fn test<T: PartialEq+Clone>(_: Option<T>) {}
|
||||||
|
Loading…
Reference in New Issue
Block a user