New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support duplicate interpolations inside a repetition #8

Closed
dtolnay opened this Issue Oct 9, 2016 · 7 comments

Comments

3 participants
@dtolnay
Copy link
Owner

dtolnay commented Oct 9, 2016

quote! { #a #a } works but quote! { #(#a #a)* } does not.

@dtolnay dtolnay added the enhancement label Oct 9, 2016

@dtolnay

This comment has been minimized.

Copy link
Owner

dtolnay commented Jan 3, 2017

I don't think this is possible with quote! being a macro_rules! macro because macro_rules does not expose any way to compare idents for equality.

Rewriting quote! as a procedural macro (using proc-macro-hack) would make it possible to fix this but I would prefer to wait until functionlike!() procedural macros are supported for real.

@purpleposeidon

This comment has been minimized.

Copy link

purpleposeidon commented Feb 25, 2017

This is the work-around I have been using for this issue:

let a2 = &a
quote! { #(#a #a2)* }
@purpleposeidon

This comment has been minimized.

Copy link

purpleposeidon commented Feb 25, 2017

Nope, that doesn't actually compile!

#[macro_use]
extern crate quote;

fn main() {
    let foo: Vec<&str> = Vec::new();
    let foo2 = &foo;
    quote! {
        #(#foo #foo2)*
    };
}
error[E0505]: cannot move out of `foo` because it is borrowed
 --> src/main.rs:7:5
  |
6 |       let foo2 = &foo;
  |                   --- borrow of `foo` occurs here
7 |       quote! {
  |  _____^ starting here...
8 | |         #(#foo #foo2)*
9 | |     };
  | |______^ ...ending here: move out of `foo` occurs here
  |
  = note: this error originates in a macro outside of the current crate

--pretty expanded makes it obvious why:

fn main() {
    let foo: Vec<&str> = Vec::new();
    let foo2 = &foo;
    {
        let mut _s = $crate::Tokens::new();
        for (foo, foo2) in foo.into_iter().zip(foo2) {
            $crate::ToTokens::to_tokens(&foo, &mut _s);
            $crate::ToTokens::to_tokens(&foo2, &mut _s);
        };
        _s
    };
}
@dtolnay

This comment has been minimized.

Copy link
Owner

dtolnay commented Feb 25, 2017

let ref foo: Vec<&str> = Vec::new();
let foo2 = foo;
quote! {
    #(#foo #foo2)*
};
@JeanMertz

This comment has been minimized.

Copy link

JeanMertz commented Sep 11, 2018

For reference, I ran into this today.

I am porting a fairly complex macro_rules! macro to a proc-macro implementation, using quote! as the first step to keep as much of the existing code the same. As soon as I got to some of the repetition parts, it failed with this error.

Since funclike proc-macro's are (almost?) a thing now, perhaps it's time to start thinking about that rewrite for quote! as well (I'm saying this, knowing full well that such a thing takes time, and time is something we could all use a bit more).

Until that moment, is the best workaround to do the looping outside of quote! and use extend to stitch multiple quotes together?

Not sure why I didn't realise the post above was the current workaround, but that works as expected 👍

Feliix42 added a commit to ohua-dev/ohua-rust-runtime that referenced this issue Dec 14, 2018

Fix compilation errors
As pointed out in dtolnay/quote#8, the workaround is required due to
limitations of the `macro_rules!` macro. I hope this can be removed
someday.
@dtolnay

This comment has been minimized.

Copy link
Owner

dtolnay commented Jan 28, 2019

Closing as an acknowledged limitation that I don't intend to fix. dtolnay/request-for-implementation#8 tracks a procedural macro reimplementation of quote (as a separate library) which will be able to avoid this limitation. Maybe crates that hit this especially often will opt to use the other library.

The recommended workaround is to use references with distinct names inside the repetition.

let a: Vec<_> = /* ... */;
let a1 = &a;
let a2 = &a;
quote! {
    #(#a1 #a2)*
};

@dtolnay dtolnay closed this Jan 28, 2019

@dtolnay

This comment has been minimized.

Copy link
Owner

dtolnay commented Jan 28, 2019

Added an indication of the limitation in the docs: f81fdb4.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment