Then your proposal would be to have X::_(y) to expand to X::A(y) | X::B(y) | X::C(y). Which is probably not great because, what if I add another enum variant that doesn't have the same parameters? Like
enum X {
A(i32),
B(i32),
C(i32),
D(String, String),
}
(or even single-variant patterns, just to transform into Option, though now that we have if let those are likely less useful, other than being able to ? them sometimes).
This is a design choice, but if everyenum Scalar variant has exactly the same data, that suggests to me that it should really be a struct Scalar with direct fields and a data-less enum kind: ScalarKind. Then you can also be sure that the compiler doesn't have to optimize away all the matching when you access the common data.
But we have to write many patterns for every enum like this. And if I only have one method to do this thing, I just need move the pattern's code into that method.
the problem of doing this with a macro is that if you refactor the type to for eg. remove a variant or change its payload, the type error will confusingly happen in the function that calls the macro, and not in the pattern definition itself.
It's like the difference between Rust generics and C++ templates.
IMHO this is not always a valid objection. Generics could also be replaced by macros (consider templates in C++), and there are good reasons why we don't go that way. Pattern synonyms can have their own signatures which are validated by the compiler, and when we encounter them in pattern position (e.g., in a match expression), the syntax should be exactly the same as normal patterns, so we know what to expect; but for macros, anything could happen in a macro invocation, because the syntax is not pre-determined and enforced by a compiler.
Together with something like ViewPatterns in Haskell it would become very useful e.g. for high-quality Rust bindings for existing libraries. Consider for example we want a high-level binding for LLVM with the ability to pattern match on its internal IR structures, it could be done by providing a series of accessor functions try_get_VariantX_from_EnumY: fn(&EnumY) -> Option<&VariantX> (backed by the foreign implementation), and define EnumY::VariantX as a (refutable) view pattern using that accessor function. Additionally with opaque types it would be possible to work with foreign libraries just like normal Rust libraries.