This is similar to the initial proposal in #110, with a few changes.
1. If an `Ident` was used to provide a fragment within the final formatted
string, the default behaviour has been changed to inheret the `Span` from it.
The idea here is to produce good spans for formatted identifiers by default,
attributing them to the source of their name.
The `span` named argument can still be used to override this decision.
2. `Ident::new(...)` doesn't support creating raw identifiers, and
`Ident::new_raw` is still unstable, so the initial behaviour of directly
passing the result of `format!` into `Ident::new(...)` turned out not to
work.
Instead, a helper method was added, `__rt::mk_ident`, which will handle
creating raw identifiers using the roundabout "parse as TokenStream and
unwrap" approach.
I thought it was important to support raw identifiers in `format_ident!` as
people may want to be able to write `format_ident!("r#{}_{}", a, b)` or
similar to ensure that their identifiers are never confused for keywords.
3. It turns out it's basically impossible to compare spans right now, and
there's no stable way to produce a span other than `Span::call_site()`, so no
tests check that the spans are passed around correctly.
This eliminates the restrictions around duplicate interpolations by taking
advantage of shadowing of let bindings within generated loops and rust deref
coersion within a desugared loop.
Duplicate calls to `IntoIter::into_iter` are handled, as the duplicates will be
called on the already-bound iterator objects, meaning that the call is a no-op.
Duplicate calls to `next()` are also handled by wrapping each interpolation
within the loop into a `RepInterp<T>` wrapper. This wrapper provides a dummy
inherent `next` method which ensures that `next` is only called once per
iterator per loop.
As a side-benefit, this has the effect of producing `unused_code` warnings when
no interpolations occur within a repetition block, as rustc can see an
unconditional break statement before code to generate the repetition body.
This has been tested working in rustc 1.15.1, although extraneous `unused_mut`
warnings are emitted due to `#[allow(unused_mut)]` being ignored on statements
in that release.
The generated code looks similar to the following:
```rust
// quote!(#(#a #b #a),*);
// ...
{
let mut _i = 0; // Only used if sep is present.
// Get and bind iterators to use for the capture repetition.
#[allow(unused_mut)] let mut a = a.into_iter();
#[allow(unused_mut)] let mut b = b.into_iter();
// Duplicate names are a no-op, as IntoIter::into_iter is idempotent.
#[allow(unused_mut)] let mut a = a.into_iter();
loop {
// Calls `Iterator::next` and wraps the result in `RepInterp` if `Some`.
let a = match a.next() {
Some(_x) => $crate::__rt::RepInterp(_x),
None => break,
};
let b = match b.next() {
Some(_x) => $crate::__rt::RepInterp(_x),
None => break,
};
// No-op `next()` call for duplicate names, as `RepInterp` defines an
// inherent `next(self) -> Option<T>` method.
let a = match a.next() {
Some(_x) => $crate::__rt::RepInterp(_x),
None => break,
};
if _i > 0 {
quote_each_token!(tokens span ,);
}
_i += 1;
quote_each_token!(tokens span #a #b #a);
}
}
// ...
```