I'm writing a derive macro, so I can get all the generics from DeriveInput, but I can't figure out how to get the individual generics. All syn eposes for each field of each variant is a Type, but it doesn't say if the Type is generic over anything, and if so, what that generic parameter is.
Procedural macros don't have access to type checking since they run before type checking does. You can manually compare the types in the variants to see if they match the generic parameter name (iirc they should be Paths with a single Ident if they're generic parameters).
It's not fun, but if you know what your use case is use can just throw an error if the enum does anything more complicated (like use a reference to a generic parameters instead of a value) and that simplifies things a bit at least.
So some of the PhantomData's generics would be extraneous, but we wouldn't need to figure out types as we can use syn's TypeGenerics. Do you know if this would have any effects on variance and typey stuff?
You could do that with PhantomData<*const (T, U)> but that will have implications for the usability of the structs since they'll have a bunch of extra type parameters which can't be inferred easily in other contexts.
By reading this code, you, as a human developer, can say that this type Hello is an enum with two generic parameters T and U and its first variant Tee only uses the parameter T etc. How did you know that? Just like you, proc macro derives can also read this code. All you need to do is to translate your in-brain algorithm into proc macro code.
enum Hello<T, U> means the name T and U are generic parameters. If a variant mentions that names it contains mentioned generic parameters.
I'm not sure how to do that through syn's API though, and I don't want to hand write a parser for enums. I think I could start by parsing the ToTokens output of the TypeGenerics struct from syn, since it doesn't have any useful methods.
I also completely forgot that lifetimes fall into the same category as type generics parsing-wise, so supporting generics might be more effort than is worth it.
@fprasx whilst there are some very contrived scenarios where parsing, alone, is unable to tell you which parameters are definitely used, in practice, nobody would write code that contrived, or, at least, you could have extra optional annotations be required by those wanting something that crazy.
To clarify, I'm talking of things like <T as IdentityIgnoring<U>::Itself which, for some conveniently defined trait IdentityIgnoring<U>, would resolve to T, and thus ignore U, despite featuring both T and U (this is, by the way, they way to write type aliases which disregard parameters).
So, in 99.9% of the cases, if a type mentions / names another type inside it, it's a fair heuristic to consider that type as being used.