winnow-rs / winnow

Making parsing a breeze
https://docs.rs/winnow
Other
573 stars 46 forks source link

Diverging expressions causing errors in `dispatch!` #551

Open BLucky-gh opened 5 months ago

BLucky-gh commented 5 months ago

Please complete the following tasks

rust version

rustc 1.78.0 (9b00956e5 2024-04-29)

winnow version

0.6.13

Minimal reproducible code

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=92bbd4c2222748d4082d828411b9ff61

extern crate winnow; // 0.6.13

use winnow::{
    combinator::{dispatch, empty},
    token::any,
    PResult, Parser,
};

fn main() {
    let mut input = "ababab";
    let res = parse.parse_next(&mut input);
    assert_eq!(res, Ok(1));
    assert_eq!(input, "babab");
}

fn parse(input: &mut &str) -> PResult<u8> {
    dispatch!(any;
        'a' => empty.value(1),
        'b' => empty.value(2),
        _ => unreachable!()
    )
}

Steps to reproduce the bug with the above code

just try to compile the code. Either through cargo run or build or check

Actual Behaviour

the macro tries to expand it to unreachable!().parse_next(...) which causes the following error:

error[E0599]: the method `parse_next` exists for type `!`, but its trait bounds were not satisfied
  --> src/main.rs:17:5
   |
17 | /     dispatch!(any;
18 | |         'a' => empty.value(1),
19 | |         'b' => empty.value(2),
20 | |         _ => unreachable!()
21 | |     )
   | |_____^ method cannot be called on `!` due to unsatisfied trait bounds
   |
   = note: the following trait bounds were not satisfied:
           `<! as FnOnce<(&mut _,)>>::Output = Result<_, ErrMode<_>>`
           which is required by `!: Parser<_, _, _>`
           `!: FnMut<(&mut _,)>`
           which is required by `!: Parser<_, _, _>`
   = note: this error originates in the macro `dispatch` (in Nightly builds, run with -Z macro-backtrace for more info)

Expected Behaviour

The macro should try to ignore unreachable expressions, or maybe include a blanket implementation of Parser for ! that is just unreachable!() or even unreachable_unchecked() for all required methods as a stopgap measure just to satisfy the compiler?

Additional Context

The compiler should realistically be able to detect that the "method" on ! will never be called, but since it doesn't I guess the library would need to handle it

for now I'll just do a _ => empty.map(|_| unreachable!())

baoyachi commented 5 months ago

Reference:https://github.com/rust-lang/rust/issues/35121

BLucky-gh commented 5 months ago

Oh it got destabilized again, yeah in that case I guess we just gotta wait until the feature is stable before this can be fixed

epage commented 5 months ago

Would the todo parser help?

BLucky-gh commented 5 months ago

while it reaches the same conclusion (aka panic), 1) the parser's name in the code implies that branch is unfinished rather than unreachable, 2) it has a different panic message