Skip to content

#[warn(non_shorthand_field_patterns)] is a menace to pattern macros #49588

Closed
@ExpHP

Description

@ExpHP

Nobody responded to my URLO thread, and the rabbit hole has only gotten deeper and deeper since I've started trying to work around this in frunk's hlist_pat. It's time for an issue.

Here's a simple pattern macro:

pub struct Value<A> { pub value: A }

#[macro_export]
macro_rules! pat {
    ($a:pat) => { Value { value: $a }};
}

Trouble is, suppose somebody writes pat!(value). Then they'll get this:

warning: the `value:` in this pattern is redundant
 --> src/main.rs:5:27
  |
5 |     ($a:pat) => { Value { value: $a }};
  |                           ^^^^^ help: remove this
...
9 |     let pat!(value) = Value { value: () };
  |         ----------- in this macro invocation
  |
  = note: #[warn(non_shorthand_field_patterns)] on by default

    Finished dev [unoptimized + debuginfo] target(s) in 0.45 secs
     Running `target/debug/playground`

Here is the simplest alternative I can come up with for working around this warning in this simple macro.

macro_rules! pat {
    // Possibly rewrite ident patterns to avoid 'value: value'.
    // We need to duplicate the ident in an intermediate rule first
    // so we can match the ident to a literal without losing hygiene.
    (ref mut $a:ident) => { pat![%HACK% [ref mut] $a $a] };
    (ref $a:ident)     => { pat![%HACK% [ref]     $a $a] };
    (mut $a:ident)     => { pat![%HACK% [mut]     $a $a] };
    ($a:ident)         => { pat![%HACK% []        $a $a] };
    
    // only the specific ident 'value' should be rewritten,
    // since otherwise we might rewrite unit structs or constants.
    (%HACK% [$($kw:tt)*] $ident:ident value ) => { Value { $($kw)* $ident } };
    (%HACK% [$($kw:tt)*] $ident:ident $_x:tt) => { Value { value: $($kw)* $ident } };
    
    // if it is any other kind of pattern, use it normally
    ($a:pat) => { Value { value: $a }};
}

Notice how proper support for ref and mut requires that the macro output uses shorthand field syntax, as opposed to a more scalable workaround like value: value@_ (where the value@_ is at least something that could be produced by a helper macro). A similar pattern macro for a struct with two fields basically requires an incremental muncher now, just to avoid the exponential blowup of 5^n rules.

This is an awful lot of headache just for a little reminder to write more idiomatic code! Isn't that clippy's job, anyhow?

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-diagnosticsArea: Messages for errors, warnings, and lintsA-macrosArea: All kinds of macros (custom derive, macro_rules!, proc macros, ..)C-enhancementCategory: An issue proposing an enhancement or a PR with one.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions