Skip to content

Parsing inconsistencies (lambda, proc, return) #28784

Description

@rprichard

I found more inconsistencies between rustc and parser-lalr.

I also noticed that Rust allows return expressions and lambda expressions to end with a struct literal, even when they're in a nostruct context. This seems inconsistent to me.

Lambdas (the two parsers disagree):

struct A { a: i32 }
fn lambda_expr_nostruct() -> A {
    // rustc accepts this, but parser-lalr does not.
    match || A { a: 123 } {
        f => f()
    }
}

Return expressions (the two parsers agree):

struct A { a: i32 }
fn return_ambiguity_1() -> A {
    match A { a: 1 } { x => x } // rejected by rustc and parser-lalr
}
fn return_ambiguity_2() -> A {
    match return A { a: 1 } { _ => A { a: 1 } } // accepted by rustc and parser-lalr
}

The rustc and parser-lalr parsers disagree about whether a bare return expression can be cast:

fn cast_of_return() {
    // rustc rejects, parser-lalr accepts
    // error: expected identifier, found keyword `as`
    return as ();
    (return as ());

    return == (); // rustc accepts, parser-lalr accepts
    loop {
        continue as (); // rustc accepts, parser-lalr accepts
        continue == (); // rustc accepts, parser-lalr accepts
        break as ();    // rustc accepts, parser-lalr accepts
        break == ();    // rustc accepts, parser-lalr accepts
    };
}

Finally, I also noticed these two differences, which seem much less interesting to me. The grammar is probably just out-of-date or buggy:

lambda sometimes requires braces:

fn lambda_braces() {
    // parser-lalr accepts this, but rustc does not.  I think this is an
    // obvious bug in the parser-lalr.y grammar.  If there is a return type,
    // then curly braces are required.
    let _x = || -> i32 10;
}

proc is obsolete:

fn proc_syntax() {
    // parser-lalr also accepts this.  I think the proc syntax is obsolete, and
    // the {proc_expr, proc_expr_nostruct} non-terminals could be removed from
    // parser-lalr.y.
    let _x = proc() {};
}

Activity

  1. steveklabnik commented on Oct 4, 2015

    @steveklabnik
    Contributor

    /cc @rust-lang/lang , can we disambiguate what's intended here?

  2. added
    A-parserArea: The lexing & parsing of Rust source code to an AST
    on Oct 6, 2015
  3. nikomatsakis commented on Oct 6, 2015

    @nikomatsakis
    Contributor

    I agree with @rprichard's take for the most part. I guess that return as i32 ought to parse...weird as it is.

    triage: P-medium

  4. added
    T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
    on Oct 6, 2015
  5. added
    P-lowLow priority
    E-easyCall for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue.
    and removed on Jul 14, 2016
  6. brson commented on Jul 14, 2016

    @brson
    Contributor

    Probably a good beginner bug for someone familiar with parsing.

  7. brson commented on Jul 15, 2016

    @brson
    Contributor

    Make the rustc parser behavie like parser-lalr, per the op.

  8. neunenak commented on Jul 20, 2016

    @neunenak
    Contributor

    I'm reaaonably familiar with parsers and I'd like to take a crack at this bug.

  9. brson commented on Jul 20, 2016

    @brson
    Contributor

    @neunenak You got it!

  10. brson commented on Jul 20, 2016

    @brson
    Contributor

    @nikomatsakis @nrc @pnkfelix Can you confirm the right thing to do here is make libsyntax behave like the reference parser as described in the OP?

  11. nrc commented on Jul 20, 2016

    @nrc
    Member

    It's probably worth addressing any inconsistencies between the parser the reference on an individual basis. I don't have enough faith in the reference to say it is always right.

    My opinions on the issues in the OP:

    I think return starts a new context, so it is OK to accept a struct literal after it. I don't see a parsing ambiguity there, so I think it is OK. Since the parser and reference agree, I don't think there is anything to do here.

    return expression - I thought return was a statement, so I am not qualified to offer an opinion here as my intuition is messed up. Could someone explain why it is an expression not a statement please?

    agree on the last two points - bugs in the reference.

  12. 2 remaining items

  13. neunenak commented on Jan 24, 2017

    @neunenak
    Contributor
  14. cramertj commented on Jan 24, 2017

    @cramertj
    Member

    Thanks! I took a look at the parser, and I think the issue with return is this match. Many (keyword) identifiers cannot appear at the start of an expression, as being just one of these. Should I just cover as for now, or should I match out all identifiers which cannot be in the start of an expression?

    Edit: for context, the can_begin_expr method is used by the parser to determine whether or not return is returning a value or whether it is just a bare return (see here).

  15. cramertj commented on Jan 25, 2017

    @cramertj
    Member

    I went ahead and opened #39303 fixing can_begin_expr for the as case. Let me know if I should fix it for any other keywords.

    Moving forward, what's left to do for this issue? Are all the rest just parser-lalr fixes? I don't think the lambda issue can be fixed backward-compatibly, can it? (Since we'd be stopping something from parsing that used to parse.)

    Edit: wound up making a new PR handling the remaining can_begin_expr cases on @petrochenkov's advice.

  16. nikomatsakis commented on Jan 27, 2017

    @nikomatsakis
    Contributor

    @cramertj a good question. One of my long-standing "to do" items has been to pick up work on rustypop -- in particular adding a test harness -- as a replacement for parser-lalr. When I was porting the LALR grammar, I found a number of irregularities that struck me as wrong -- often holdovers from the early days of Rust -- as well as various things whose meaning were not obvious (e.g., precedence tricks). The LALRPOP port is free of those problems.

    Separately, I think we have put off reaching a firm decision on a lot of these questions. This needs some organization and I think no one has had the time.

    I would love to find someone who would be interested in collaborating with me on one or both aspects of this project. If you are interesting, please ping me on irc (nmatsakis) or drop me an e-mail (nmatsakis@mozilla.com).

  17. cramertj commented on Jan 27, 2017

    @cramertj
    Member

    @nikomatsakis Email'd you.

  18. added
    T-langRelevant to the language team
    and removed on Mar 24, 2017
  19. colinmarsh19 commented on Oct 8, 2017

    @colinmarsh19
    Contributor

    This seems like an interesting fix. I'll take a look at it and see what I can figure out. -- Colin

  20. jonas-schievink commented on Feb 20, 2020

    @jonas-schievink
    Contributor

    parser-lalr has been removed in #64896. Closing in favor of the work done by the grammar working group in https://github.com/rust-lang/wg-grammar/.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-parserArea: The lexing & parsing of Rust source code to an ASTC-bugCategory: This is a bug.E-easyCall for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue.P-lowLow priorityT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.T-langRelevant to the language team

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions