dtolnay / paste

Macros for all your token pasting needs
Apache License 2.0
1.02k stars 56 forks source link

"Arbitrary expressions aren't allowed in patterns" error #37

Closed jordy25519 closed 4 years ago

jordy25519 commented 4 years ago

Looks like some backwards incompatible changes (semver breaking) were included in recent releases.

Since at least ~v0.1.15~v0.1.13 a down stream crate breaks with the following:

error: expected one of `...`, `..=`, `..`, `=>`, `if`, or `|`, found `..='f' | 'A'`
  --> src/json_parser.rs:21:1
   |
21 | / literals! {
22 | |     pub WhitespaceChar => '\u{0020}' | '\u{000D}' | '\u{000A}' | '\u{0009}';
23 | |     pub SignChar => '+' | '-';
24 | |     pub NegativeSignChar => '-';
...  |
35 | |     pub CloseSquareBracketChar => ']';
36 | | }
   | |_^ expected one of `...`, `..=`, `..`, `=>`, `if`, or `|`
   |
   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)

error: arbitrary expressions aren't allowed in patterns
  --> src/json_parser.rs:22:27
   |
22 |     pub WhitespaceChar => '\u{0020}' | '\u{000D}' | '\u{000A}' | '\u{0009}';
   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: arbitrary expressions aren't allowed in patterns
  --> src/json_parser.rs:23:21
   |
23 |     pub SignChar => '+' | '-';
   |                     ^^^^^^^^^

error: arbitrary expressions aren't allowed in patterns
  --> src/json_parser.rs:25:18
   |
25 |     pub EChar => 'E' | 'e';
   |                  ^^^^^^^^^

error: arbitrary expressions aren't allowed in patterns
  --> src/json_parser.rs:26:26
   |
26 |     pub OneToNineChar => '1' ..= '9';
   |                          ^^^^^^^^^^^

error: arbitrary expressions aren't allowed in patterns
  --> src/json_parser.rs:27:22
   |
27 |     pub DigitChar => '0' ..= '9';
   |                      ^^^^^^^^^^^

error[E0369]: no implementation for `char | char`
  --> src/json_parser.rs:22:38
   |
22 |     pub WhitespaceChar => '\u{0020}' | '\u{000D}' | '\u{000A}' | '\u{0009}';
   |                           ---------- ^ ---------- char
   |                           |
   |                           char

error[E0369]: no implementation for `char | char`
  --> src/json_parser.rs:23:25
   |
23 |     pub SignChar => '+' | '-';
   |                     --- ^ --- char
   |                     |
   |                     char

error[E0369]: no implementation for `char | char`
  --> src/json_parser.rs:25:22
   |
25 |     pub EChar => 'E' | 'e';
   |                  --- ^ --- char
   |                  |
   |                  char

error[E0308]: mismatched types
  --> src/json_parser.rs:21:1
   |
21 | / literals! {
22 | |     pub WhitespaceChar => '\u{0020}' | '\u{000D}' | '\u{000A}' | '\u{0009}';
23 | |     pub SignChar => '+' | '-';
24 | |     pub NegativeSignChar => '-';
...  |
35 | |     pub CloseSquareBracketChar => ']';
36 | | }
   | | ^
   | | |
   | |_expected `char`, found struct `std::ops::RangeInclusive`
   |   this expression has type `char`
   |
   = note: expected type `char`
            found struct `std::ops::RangeInclusive<char>`
   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0308]: mismatched types
  --> src/json_parser.rs:21:1
   |
21 | / literals! {
22 | |     pub WhitespaceChar => '\u{0020}' | '\u{000D}' | '\u{000A}' | '\u{0009}';
23 | |     pub SignChar => '+' | '-';
24 | |     pub NegativeSignChar => '-';
...  |
35 | |     pub CloseSquareBracketChar => ']';
36 | | }
   | | ^
   | | |
   | |_expected `char`, found struct `std::ops::RangeInclusive`
   |   this expression has type `char`
   |
   = note: expected type `char`
            found struct `std::ops::RangeInclusive<char>`
   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)

code link: https://github.com/xlc/lite-json/blob/82d863506b652790c49df9b0fa0ceda87f600ee0/parser/src/parser.rs#L237-L256

Update

jordy25519 commented 4 years ago

Unfortunately I'm not familiar with this or the downstream crate enough to reproduce. Further investigation shows this works fine in v0.1.12 and in v0.1.13 breaks with the logs above. Relevant code:

    (
        IMPL
        $( #[ $attr:meta ] )*
        $vis:vis $name:ident => $($value:tt)+
    ) => (
        $crate::paste::item! {
            $vis struct [< $name Predicate >];
            impl $crate::parser::Predicate<char> for [< $name Predicate >] {
                fn eval(c: &char) -> bool {
                    match *c {
                        $($value)+ => true,
                        _ => false
                    }
                }
            }

            $( #[ $attr ] )*
            $vis type $name = $crate::parser::ExpectChar<[< $name Predicate >]>;
        }
    );
dtolnay commented 4 years ago

We must have been doing something to trigger a compiler bug before, but I don't know what. Even if you remove paste that macro by itself produces exactly those same errors.

#[macro_export]
macro_rules! literals {
    (
        $(
            $( #[ $attr:meta ] )*
            $vis:vis $name:ident => $($value:expr)+;
        )*
    ) => {
        $(
            $crate::literals!{
                IMPL
                $( #[ $attr ] )*
                $vis $name => $($value)+
            }
        )*
    };
    (
        IMPL
        $( #[ $attr:meta ] )*
        $vis:vis $name:ident => $($value:tt)+
    ) => {
        $vis struct $name;
        impl Predicate<char> for $name {
            fn eval(c: &char) -> bool {
                match *c {
                    $($value)+ => true,
                    _ => false
                }
            }
        }
    };
}

trait Predicate<T> {
    fn eval(c: &T) -> bool;
}

literals! {
    pub WhitespaceChar => '\u{0020}' | '\u{000D}' | '\u{000A}' | '\u{0009}';
    pub SignChar => '+' | '-';
    pub NegativeSignChar => '-';
    pub EChar => 'E' | 'e';
    pub OneToNineChar => '1' ..= '9';
    pub DigitChar => '0' ..= '9';
    pub DotChar => '.';
    pub HexChar => '0' ..= '9' | 'a' ..= 'f' | 'A' ..= 'F';
    pub DoubleQuoteChar => '"';
    pub OpenCurlyBracketChar => '{';
    pub CloseCurlyBracketChar => '}';
    pub CommaChar => ',';
    pub OpenSquareBracketChar => '[';
    pub CloseSquareBracketChar => ']';
}
dtolnay commented 4 years ago

Fixed in lite-json 0.1.1 by https://github.com/xlc/lite-json/commit/783adb89a17412184747ed427118c026108448e9.

I don't know if there is anything we can do to intentionally trigger the same compiler bug that was causing it to work before, so I'll go ahead and close this now that the most recent version of lite-json does compile.