rust-lang / wg-grammar

Where the work of WG-grammar, aiming to provide a canonical grammar for Rust, resides
Apache License 2.0
99 stars 20 forks source link

How to handle brace expression restrictions? #53

Open ehuss opened 5 years ago

ehuss commented 5 years ago

Various places do not allow struct expressions. All of the following fail to parse in libsyntax, but pass in the current lyg grammar:

if S{a:1} {} if let x=S{a:1} {} while S{a:1} {} while let x=S{a:1} {} for pat in S{a:1} {} match S{a:1} {}

This restriction applies recursively (I'm not sure how to express this), that is the following is also rejected:

if x==S{a:1} {}

if S{a:1}.foo() {}

I included a field just because rustc will give a helpful suggestion, whereas a fieldless expression gets confused by the second {} which rustc just treats an independent block, as this hilarious example shows:

#[derive(PartialEq)]
struct S;
let x = S;
if x != S{} {
    // This block is executed because it is not part of the `if` expression, 
    // even though it appears to be. 
    println!("hm, x!=S{} should be false");
}

Should this kind of ambiguity rejection be part of the syntax?

See https://github.com/rust-lang/rust/pull/59981 for some examples, and where this was recently changed. See also https://github.com/rust-lang-nursery/reference/issues/569.

CAD97 commented 5 years ago

For the if x != S{} { /* block */ } version, this has to parse the way it currently does, to allow the perfectly legal and normal code of comparing two variables in a condition. Here we just have to lean on rustfmt formatting, I guess.

ehuss commented 5 years ago

Oh, I'm not implying it is wrong for libsyntax to interpret it the way it does. Although a warning might be nice, this is a contrived example that I doubt anyone would ever write.

I'm more trying to understand how the grammar can be written to express this behavior. libsyntax uses "restrictions", and in https://github.com/rust-lang-nursery/wg-grammar/pull/13#issuecomment-436125874 @eddyb mentioned the open question of how to handle this. #39 is another example where restrictions need to be expressed.

Is it on the table for the GLL parser to be able to express these directly? If not, then it seems you have to bifurcate the definitions (ExprNoStruct would have all expressions except Struct, but that would require recursively copying all the expressions, which I think would be terrible).

What are the options for handling these kinds of restrictions?

Centril commented 5 years ago

I think https://github.com/rust-lang/gll/issues/27 could be a way to handle it with "flags".

I did something similar in the specification of or-patterns, https://github.com/rust-lang/rfcs/blob/master/text/2535-or-patterns.md#grammar.