dtolnay / quote

Rust quasi-quoting
Apache License 2.0
1.32k stars 90 forks source link

Option<T> repetitions do not work #213

Closed lroux-at-jellysmack closed 2 months ago

lroux-at-jellysmack commented 2 years ago

Hello,

While trying to do the following thing,

fn test(option: Option<TokenStream>) -> TokenStream {
    quote! {
        #(#option)*
    }
}

it gives me the following error:

expected struct `HasIterator`, found struct `ThereIsNoIteratorInRepetition`

The type Option<T> does not work in repetitions (#()*), while stated otherwise in the README.md here, since Option<T> implements IntoIterator.

I also found something stating the inverse here:

The variables in an interpolation may be a Vec, slice, BTreeSet, or any Iterator.

I ended up fixing my code by doing this:

 fn test(option: Option<TokenStream>) -> TokenStream {
+    let option = option.iter();
     quote! {
         #(#option)*
     }
 }

Also I have a few questions:

Thanks :)

ahl commented 2 years ago

This may not address your actual use, but you can just do

fn test(option: Option<TokenStream>) -> TokenStream {
    quote! {
        #option
    }
}

This precludes other fancy stuff you might want to do inside the #( ... )* repetition specifier.

Agreed that the docs appear to be inaccurate based on the current implementation: https://github.com/dtolnay/quote/blob/ae25ab6a5bde0efc79d85a8211b76d0bdd08dca7/src/runtime.rs#L54

coolreader18 commented 1 year ago

This might count as a breaking change, but what if there was a #( #var )? optionality specifier? Basically the same as #()* but expecting the variable to be an option

cyqsimon commented 11 months ago

Ran into this problem today with a vector of options. Confused the heck out of me. Ended up doing this. Not particularly pretty but it works.

let vec_of_options: Vec<Option<String>> = vec![/* stuff */];
let vec_of_options_tokenised: Vec<TokenStream> = vec_of_options
    .into_iter()
    .map(|opt| match opt {
        Some(text) => quote! { Some(#text) },
        None => quote! { None },
    })
    .collect();
// in quote macro, use `vec_of_options_tokenised` instead of `vec_of_options`
dtolnay commented 2 months ago

or

or

are the recommended solutions.

I put up #280 to fix the documentation about "anything that implements IntoIterator".