Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

parse_quote! fails for Punctuated<Arm, Comma> #1795

Closed
vic1707 opened this issue Dec 21, 2024 · 5 comments · Fixed by #1796
Closed

parse_quote! fails for Punctuated<Arm, Comma> #1795

vic1707 opened this issue Dec 21, 2024 · 5 comments · Fixed by #1796

Comments

@vic1707
Copy link

vic1707 commented Dec 21, 2024

this code (minimal example)

/* using: syn = { version = "2.0.90", features = ["full", "extra-traits"] } */

use syn::{parse_quote, punctuated::Punctuated, token::Comma, Arm};

fn main() {
    let i: Punctuated<Arm, Comma> = parse_quote!(
        true => 12,
        false => 13,
    );
    println!{"{i:#?}"};
}

results in an error

  zsh ❯ RUST_BACKTRACE=full cargo run --example tt
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.03s
     Running `/Users/vic1707/Desktop/tests/target/debug/examples/tt`
thread 'main' panicked at examples/tt.rs:4:37:
expected `,`
stack backtrace:
   0:        0x10302c538 - std::backtrace_rs::backtrace::libunwind::trace::h6285d60e8a2c022a
                               at /rustc/90b35a6239c3d8bdabc530a6a0816f7ff89a0aaf/library/std/src/../../backtrace/src/backtrace/libunwind.rs:116:5
   1:        0x10302c538 - std::backtrace_rs::backtrace::trace_unsynchronized::h21fc036d4b8dd7fe
                               at /rustc/90b35a6239c3d8bdabc530a6a0816f7ff89a0aaf/library/std/src/../../backtrace/src/backtrace/mod.rs:66:5
   2:        0x10302c538 - std::sys::backtrace::_print_fmt::h69654d1f9cd065f2
                               at /rustc/90b35a6239c3d8bdabc530a6a0816f7ff89a0aaf/library/std/src/sys/backtrace.rs:66:9
   3:        0x10302c538 - <std::sys::backtrace::BacktraceLock::print::DisplayBacktrace as core::fmt::Display>::fmt::h7adefaad4a31afc0
                               at /rustc/90b35a6239c3d8bdabc530a6a0816f7ff89a0aaf/library/std/src/sys/backtrace.rs:39:26
   4:        0x103040448 - core::fmt::rt::Argument::fmt::h42151196bb7af094
                               at /rustc/90b35a6239c3d8bdabc530a6a0816f7ff89a0aaf/library/core/src/fmt/rt.rs:177:76
   5:        0x103040448 - core::fmt::write::h381c0b0ce6ab972a
                               at /rustc/90b35a6239c3d8bdabc530a6a0816f7ff89a0aaf/library/core/src/fmt/mod.rs:1186:21
   6:        0x10302a7b8 - std::io::Write::write_fmt::h75af97148630d8d3
                               at /rustc/90b35a6239c3d8bdabc530a6a0816f7ff89a0aaf/library/std/src/io/mod.rs:1839:15
   7:        0x10302c3ec - std::sys::backtrace::BacktraceLock::print::h8baf33e22611de71
                               at /rustc/90b35a6239c3d8bdabc530a6a0816f7ff89a0aaf/library/std/src/sys/backtrace.rs:42:9
   8:        0x10302d2a4 - std::panicking::default_hook::{{closure}}::h369c7295ef58c5b1
                               at /rustc/90b35a6239c3d8bdabc530a6a0816f7ff89a0aaf/library/std/src/panicking.rs:268:22
   9:        0x10302d0e8 - std::panicking::default_hook::h50746358288a9d6a
                               at /rustc/90b35a6239c3d8bdabc530a6a0816f7ff89a0aaf/library/std/src/panicking.rs:295:9
  10:        0x10302da58 - std::panicking::rust_panic_with_hook::h7d795911432661cb
                               at /rustc/90b35a6239c3d8bdabc530a6a0816f7ff89a0aaf/library/std/src/panicking.rs:801:13
  11:        0x10302d70c - std::panicking::begin_panic_handler::{{closure}}::h36f15310ecbde379
                               at /rustc/90b35a6239c3d8bdabc530a6a0816f7ff89a0aaf/library/std/src/panicking.rs:674:13
  12:        0x10302c9fc - std::sys::backtrace::__rust_end_short_backtrace::heed121414170e0c7
                               at /rustc/90b35a6239c3d8bdabc530a6a0816f7ff89a0aaf/library/std/src/sys/backtrace.rs:170:18
  13:        0x10302d3c4 - rust_begin_unwind
                               at /rustc/90b35a6239c3d8bdabc530a6a0816f7ff89a0aaf/library/std/src/panicking.rs:665:5
  14:        0x10304651c - core::panicking::panic_fmt::h17b1b80ec02ffd19
                               at /rustc/90b35a6239c3d8bdabc530a6a0816f7ff89a0aaf/library/core/src/panicking.rs:74:14
  15:        0x102f18ae0 - core::panicking::panic_display::h9cf75ef08a85cd9a
                               at /Users/vic1707/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/panicking.rs:264:5
  16:        0x103044ae4 - syn::parse_quote::parse::panic_cold_display::hc7b681656d96d5d8
                               at /Users/vic1707/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/panic.rs:100:13
  17:        0x102f19b4c - syn::parse_quote::parse::h5d8560acbbbb3812
                               at /Users/vic1707/.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.90/src/parse_quote.rs:121:21
  18:        0x102f19850 - tt::main::hbbf10e05f160921c
                               at /Users/vic1707/Desktop/tests/examples/tt.rs:4:37
  19:        0x102f1a070 - core::ops::function::FnOnce::call_once::h1077c19304ab5bf5
                               at /Users/vic1707/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/ops/function.rs:250:5
  20:        0x102f18e74 - std::sys::backtrace::__rust_begin_short_backtrace::h33eda7daadad9c5b
                               at /Users/vic1707/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/src/rust/library/std/src/sys/backtrace.rs:154:18
  21:        0x102f18e0c - std::rt::lang_start::{{closure}}::hcf32816904f70aed
                               at /Users/vic1707/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/src/rust/library/std/src/rt.rs:195:18
  22:        0x103028c18 - core::ops::function::impls::<impl core::ops::function::FnOnce<A> for &F>::call_once::h1f2e4bfdaa1e9f55
                               at /rustc/90b35a6239c3d8bdabc530a6a0816f7ff89a0aaf/library/core/src/ops/function.rs:284:13
  23:        0x103028c18 - std::panicking::try::do_call::hf5f5fcb9152f95d7
                               at /rustc/90b35a6239c3d8bdabc530a6a0816f7ff89a0aaf/library/std/src/panicking.rs:557:40
  24:        0x103028c18 - std::panicking::try::hc37bea4722ea5011
                               at /rustc/90b35a6239c3d8bdabc530a6a0816f7ff89a0aaf/library/std/src/panicking.rs:520:19
  25:        0x103028c18 - std::panic::catch_unwind::h59a2106aa502b0e8
                               at /rustc/90b35a6239c3d8bdabc530a6a0816f7ff89a0aaf/library/std/src/panic.rs:358:14
  26:        0x103028c18 - std::rt::lang_start_internal::{{closure}}::h130ec563acce7cfd
                               at /rustc/90b35a6239c3d8bdabc530a6a0816f7ff89a0aaf/library/std/src/rt.rs:174:48
  27:        0x103028c18 - std::panicking::try::do_call::h406987cb4ab94a01
                               at /rustc/90b35a6239c3d8bdabc530a6a0816f7ff89a0aaf/library/std/src/panicking.rs:557:40
  28:        0x103028c18 - std::panicking::try::h3095cbba23c315df
                               at /rustc/90b35a6239c3d8bdabc530a6a0816f7ff89a0aaf/library/std/src/panicking.rs:520:19
  29:        0x103028c18 - std::panic::catch_unwind::hc35a49412f9c6ccf
                               at /rustc/90b35a6239c3d8bdabc530a6a0816f7ff89a0aaf/library/std/src/panic.rs:358:14
  30:        0x103028c18 - std::rt::lang_start_internal::h77891a2543177e4b
                               at /rustc/90b35a6239c3d8bdabc530a6a0816f7ff89a0aaf/library/std/src/rt.rs:174:20
  31:        0x102f18dd8 - std::rt::lang_start::h912d3342bd4e7f74
                               at /Users/vic1707/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/src/rust/library/std/src/rt.rs:194:17
  32:        0x102f199bc - _main

Code is parsed properly when one arm is here, but the second you add another one it fails (trailing comma or not).
I'll clone syn and try to find why + a solution but would love some advices or a fix if someone already knows where the problem is

@vic1707
Copy link
Author

vic1707 commented Dec 21, 2024

fn main() {
    let i: Punctuated<Arm, Comma> = parse_quote!(
        true => 12,,
        false => 13,
    );
    println!{"{i:#?}"};
}

is getting parsed, this is incorrect syntax but it "works"

[
    Arm {
        attrs: [],
        pat: Pat::Lit {
            attrs: [],
            lit: Lit::Bool {
                value: true,
            },
        },
        guard: None,
        fat_arrow_token: FatArrow,
        body: Expr::Lit {
            attrs: [],
            lit: Lit::Int {
                token: 12,
            },
        },
        comma: Some(
            Comma,
        ),
    },
    Comma,
    Arm {
        attrs: [],
        pat: Pat::Lit {
            attrs: [],
            lit: Lit::Bool {
                value: false,
            },
        },
        guard: None,
        fat_arrow_token: FatArrow,
        body: Expr::Lit {
            attrs: [],
            lit: Lit::Int {
                token: 13,
            },
        },
        comma: Some(
            Comma,
        ),
    },
    Comma,
    Arm {
        attrs: [],
        pat: Pat::Lit {
            attrs: [],
            lit: Lit::Bool {
                value: false,
            },
        },
        guard: None,
        fat_arrow_token: FatArrow,
        body: Expr::Lit {
            attrs: [],
            lit: Lit::Int {
                token: 13,
            },
        },
        comma: Some(
            Comma,
        ),
    },
]

I feel like the comma is part of the Arm struct itself, so punctuated requires a second one.
This makes sense but also implies parse_quote! can't parse multiple match arms or am I mistaking it ?

A simple idea would be to prioritize taking the trailing comma for the punctuated sequence rather than for the arm but I feel like this can lead to a number of other issues 🤔

@dtolnay
Copy link
Owner

dtolnay commented Dec 22, 2024

The optional trailing comma is already included inside Arm, so Punctuated<Arm, Token![,]> is never a type that would make sense to use.

You can use Vec<Arm> instead, which is also the form in which Expr::Match holds the match arms.

@vic1707
Copy link
Author

vic1707 commented Dec 22, 2024

Thank you for this, I didn't consider asking for Vec<Arm> it works great 👍
quick question:
a Vec<Attribute> like that works

let i: Vec<Attribute> = parse_quote!(
        #[derive(Deserialize, Serialize)]
        #[serde(transparent)]
);

but

let i: Vec<Arm> = parse_quote!(
        true => 12
        false => 13
);

doesn't,

let i: Vec<Arm> = parse_quote!(
        true => 12,
        false => 13
);

does, assigning the comma to the first arm.
Is it expected?

It kinda messes things up when quoting back that vec in quote! with repeat patterns
(workaround being to put the trailing comma for all arms and not use the comma as a separator in the repeat).
ie:

let i: Vec<Arm> = parse_quote!(
        true => 12,
        false => 13,
);
println!{"{i:#?}"};
let b: Vec<Arm> = parse_quote!(
        true => 12,
        #(#i)*
);
println!{"{b:#?}"};

@dtolnay
Copy link
Owner

dtolnay commented Dec 22, 2024

The repeat should not be adding new comma separators. The individual arms will already contain a trailing comma if required. Not all kinds of expressions in an arm require a trailing comma (the Rust grammar for this is complicated).

If you are not sure whether arms have a comma, for example because you are combining arms from multiple parse_quote, then you could explicitly add a comma into all arms beforehand. for arm in &mut arms { arm.comma = ... }

@vic1707
Copy link
Author

vic1707 commented Dec 22, 2024

Ok thank you 👌

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants