Repository: auto-impl-rs/auto_impl (rust)

Issue:
Error on trailing comma
The following code compiles:

```rust
#[auto_impl::auto_impl(&)]
trait MyTrait<T> {}
```

But the following code gives an error:

```rust
#[auto_impl::auto_impl(&)]
trait MyTrait<T,> {}
```

```
error: expected one of `#`, `>`, `const`, identifier, or lifetime, found `,`
 --> src/main.rs:3:1
  |
3 | #[auto_impl::auto_impl(&)]
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected one of `#`, `>`, `const`, identifier, or lifetime
  |
  = note: this error originates in the attribute macro `auto_impl::auto_impl` (in Nightly builds, run with -Z macro-backtrace for more info)
```

This is a problem when the formatter inserts trailing commas, which happens if you have lots of generics so that they wrap over to a new line:

```rust
#[auto_impl::auto_impl(&)]
trait MyTrait<
    A,
    B,
    C,
    D,
> {}
```

Pull request:
Allow trailing commas in type definitions
Closes #100

Patch:
diff --git a/src/gen.rs b/src/gen.rs
index ffb8795..6c61815 100644
--- a/src/gen.rs
+++ b/src/gen.rs
@@ -1,4 +1,4 @@
-use proc_macro2::{Span as Span2, TokenStream as TokenStream2};
+use proc_macro2::{Span as Span2, TokenStream as TokenStream2, TokenTree as TokenTree2};
 use quote::{ToTokens, TokenStreamExt};
 use syn::{
     punctuated::Punctuated, spanned::Spanned, Attribute, Error, FnArg, GenericParam, Ident,
@@ -246,6 +246,20 @@ fn gen_header(
             .skip(1) // the opening `<`
             .collect::<Vec<_>>();
         tts.pop(); // the closing `>`
+
+        // Pop a trailing comma if there is one
+        // We'll end up conditionally putting one back in shortly
+        if tts.last().and_then(|tt| {
+            if let TokenTree2::Punct(p) = tt {
+                Some(p.as_char())
+            } else {
+                None
+            }
+        }) == Some(',')
+        {
+            tts.pop();
+        }
+
         params.append_all(&tts);
 
         // Append proxy type parameter (if there aren't any parameters so far,


Test patch:
diff --git a/tests/compile-fail/super_trait_not_implemented.stderr b/tests/compile-fail/super_trait_not_implemented.stderr
index 52513b6..96b16ef 100644
--- a/tests/compile-fail/super_trait_not_implemented.stderr
+++ b/tests/compile-fail/super_trait_not_implemented.stderr
@@ -1,4 +1,4 @@
-error[E0277]: the trait bound `Box<Dog>: Supi` is not satisfied
+error[E0277]: the trait bound `Box<Dog>: Foo` is not satisfied
   --> tests/compile-fail/super_trait_not_implemented.rs:18:18
    |
 18 |     requires_foo(Box::new(Dog)); // shouldn't, because `Box<Dog>: Supi` is not satisfied
@@ -6,7 +6,6 @@ error[E0277]: the trait bound `Box<Dog>: Supi` is not satisfied
    |     |
    |     required by a bound introduced by this call
    |
-   = help: the trait `Supi` is implemented for `Dog`
 note: required for `Box<Dog>` to implement `Foo`
   --> tests/compile-fail/super_trait_not_implemented.rs:5:1
    |
@@ -20,3 +19,7 @@ note: required by a bound in `requires_foo`
 14 | fn requires_foo<T: Foo>(_: T) {}
    |                    ^^^ required by this bound in `requires_foo`
    = note: this error originates in the attribute macro `auto_impl` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider dereferencing here
+   |
+18 |     requires_foo(*Box::new(Dog)); // shouldn't, because `Box<Dog>: Supi` is not satisfied
+   |                  +
diff --git a/tests/compile-pass/trailing_comma.rs b/tests/compile-pass/trailing_comma.rs
new file mode 100644
index 0000000..0c805b8
--- /dev/null
+++ b/tests/compile-pass/trailing_comma.rs
@@ -0,0 +1,6 @@
+use auto_impl::auto_impl;
+
+#[auto_impl(&)]
+trait MyTrait<T,> {}
+
+fn main() { }