Can syntax extensions be applied to impl methods or to whole files?


#1

Can syntax extensions be applied to impl methods? I have a working syntax extension that applies to a function, but it doesn’t seem like there’s a way to apply them to anything that’s not an ast::Item, like an impl method without applying them to the impl itself. I know syntax extensions aren’t stable, but has this issue (syntax extensions only applying to Items) been brought up/thought of before?

Also, can I write a syntax extension that can examine all the methods in a file? I know that I can apply an attribute to a module, but I have to do that above a mod declaration. Is there any way to do that inside a module itself?


#2

Not to my knowledge, no. You’ll have to apply the attribute to a mod declaration.

I’m not sure about methods, unfortunately. It might be worth filing an issue.


#3

Doesn’t #![attribute] do exactly this? I.e. applies the extension to the module it is included to, so one can write it at the top of a file and it will be effectively applied to the whole file.


#4

I don’t think the current API let’s you define that type of extension.


#5

It does. From the perspective of the compiler plugin, there’s no difference between the attribute with the bang and the one without it. The plugin would find the attribute on the item regardless of whether it was attached “inside” or “outside” the item.

I’m also not sure I understand your other question about methods in impls. You can attach attributes to them (e.g. the stability attributes) and, as far as I know, they are considered items. Could you clarify the question with an example of what you’d like to be able to do?


#6

It does. From the perspective of the compiler plugin, there’s no difference between the attribute with the bang and the one without it. The plugin would find the attribute on the item regardless of whether it was attached “inside” or “outside” the item.

Oh, I had no idea (this really needs to be documented somewhere). So just to clarify, if I do #![foo] at the top level, my plugin callback function will be passed an ItemMod, correct?

I’m also not sure I understand your other question about methods in impls.

My question is similar to the one above: what type of Item would be passed to my callback function? None of the variants seem to apply, and I asked in a few different spots and got no response that this was possible. I also made this issue.


#7

Looks like I was slightly mistaken. You’ll need to use the “MultiModifier” variant of the SyntaxExtension enum when registering your plugin. That will let you examine Items, TraitItems, and ImplItems, including methods.

I don’t have wifi right now but in a little bit I can post a sample repo for you to check out.


#8

I did see the MultiModifer variant today, but I couldn’t find any code using it. An example would be great.


#9

Posted here: https://github.com/tomjakubowski/multimodifier-example

If you add #[dare] around an impl method (and only an impl method), you’ll get a typically lame error message telling you not to use methods.

For the sake of longevity, I’ll inline the good bits here:


extern crate syntax;
extern crate rustc;

use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxExtension};
use syntax::ast::MetaItem;
use syntax::codemap::Span;
use syntax::parse::token;

use rustc::plugin::Registry;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    let nm = token::intern("dare");
    let ext = SyntaxExtension::MultiModifier(Box::new(expand_dare));
    reg.register_syntax_extension(nm, ext);
}

fn expand_dare(excx: &mut ExtCtxt,
                 sp: Span,
                 _: &MetaItem,
                 item: Annotatable) -> Annotatable {
    use syntax::ast::ImplItem_;
    if let Annotatable::ImplItem(ref iitem) = item {
        if let ImplItem_::MethodImplItem(_, _) = iitem.node {
            excx.span_err(sp, "Just Say No to methods!");
        }
    }
    item
}