Skip to content

Confusing error now saying let (not if let) is an expression, rather than a statement, which contradicts the book #65254

Description

@carols10cents

cc @Centril

Code first. This code:

fn main() {
    let x = (let y = 6);
}

on current stable Rust 1.38, gives this set of error messages:

error[E0658]: `let` expressions in this position are experimental
 --> src/main.rs:2:14
  |
2 |     let x = (let y = 6);
  |              ^^^^^^^^^
  |
  = note: for more information, see https://github.com/rust-lang/rust/issues/53667

error: `let` expressions are not supported here
 --> src/main.rs:2:14
  |
2 |     let x = (let y = 6);
  |              ^^^^^^^^^
  |
  = note: only supported directly in conditions of `if`- and `while`-expressions
  = note: as well as when nested within `&&` and parenthesis in those conditions

warning: unnecessary parentheses around assigned value
 --> src/main.rs:2:13
  |
2 |     let x = (let y = 6);
  |             ^^^^^^^^^^^ help: remove these parentheses
  |
  = note: `#[warn(unused_parens)]` on by default

The part that I'm most concerned about is:

error: `let` expressions are not supported here

Before eRFC "if- and while-let-chains, take 2" (rust-lang/rfcs#2497, #53667, #53668), this code USED to result in this error message:

error: expected expression, found statement (`let`)
 --> src/main.rs:2:14
  |
2 |     let x = (let y = 6);
  |              ^^^
  |
  = note: variable declaration using `let` is a statement

The reason I know this is because we have the old error message in the book, in the section where we're trying to explain the difference between statements and expressions. The error message I'm seeing now is muddying the waters by saying "let expressions".

Based on my reading of the eRFC, it's only supposed to change if let, but as kind of a side effect let is now sort-of an expression? The updates to the reference don't clear it up for me, as they only describe if let, not plain lets.

What I expected is that even though the eRFC has been accepted and implemented, plain let y = 6 would still be considered a statement and the error message wouldn't talk about "let expressions".

If my expectation is valid, then the compiler error message is a bug. If my expectation is invalid, please let me know so that I can work on updating the book. Thanks!

This issue has been assigned to @jafern14 via this comment.

Activity

  1. Centril commented on Oct 10, 2019

    @Centril
    Contributor

    Also added notes in #docs if sync discussion is desired.


    So the new compiler error, introduced in #60861, here is by design and tested in https://github.com/rust-lang/rust/blob/master/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs which has more notes. Specifically, the error here comes from HIR lowering.

    The idea is that "let" $pat "=" $expr is a syntactically valid expression in all cases (on nightly). The distinction between semantic and syntactic can be noticed via macros and conditional compilation. Semantically however, let is only allowed in the cases that disallowed-positions.rs notes, namely the cases generated by the grammar Expr:

    Expr =
      | ...
      | "if" ExprWithLet Block {"else" Block}?
      | {Label ":"}? "while" ExprWithLet Block
      ;
    
    ExprWithLet =
      | "let" PatTop "=" Expr
      | ExprWithLet "&&" ExprWithLet 
      | "(" ExprWithLet ")"
      | Expr
      ;

    Eventually however, e.g. with a follow-up RFC, I would like to turn let into a true semantic expression typed at bool such that e.g. if !let Foo::Bar = x { ... } becomes legal. So overall the goal is to "muddy the waters".

    The reference has not been updated because we only make updates to it once a feature becomes stable.


    With all that said, I'm open to tweaks to the error message (it's optimized for suggesting that e.g. if foo || let A(x) = bar { ... } is not legal). For example, we could have a different note for stable compilers or when the feature gate is not active. cc @estebank

  2. added
    A-diagnosticsArea: Messages for errors, warnings, and lints
    T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
    D-confusingDiagnostics: Confusing error or lint that should be reworked.
    A-let-chainsArea: let chains (if-let, while-let, ...)
    on Oct 10, 2019
  3. carols10cents commented on Oct 10, 2019

    @carols10cents
    MemberAuthor

    I would be happy with a different error message for stable compilers that continued to call let outside of if let a statement rather than an expression.

  4. Centril commented on Oct 10, 2019

    @Centril
    Contributor

    Should be easy to implement by tweaking the HIR lowering code just a tiny bit. Will try to do that sometime during the week but no firm promises. :)

  5. self-assigned this
    on Oct 10, 2019
  6. Centril commented on Oct 10, 2019

    @Centril
    Contributor

    ...but if anyone wants to work-steal this from me then this would be a good first issue.

    You'll want to tweak LoweringContext::lower_expr_let by keeping the current wording when self.sess.parse_sess.unstable_features.is_nightly_build() holds and changing it to @carols10cents's suggested wording (the old one) otherwise.

  7. added
    E-easyCall for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue.
    E-help-wantedCall for participation: Help is requested to fix this issue.
    E-mentorCall for participation: This issue has a mentor. Use #t-compiler/help on Zulip for discussion.
    on Oct 10, 2019
  8. estebank commented on Oct 10, 2019

    @estebank
    Contributor

    There's precedent for different messages depending on whether the current compiler is stable or not and whether there's a feature flag enabled or not. I don't think all three cases are needed here and just gate on the feature being enabled.

  9. Manishearth commented on Oct 10, 2019

    @Manishearth
    Member

    I'd go further to say that we should be doing what @estebank describes most of the time: unless a feature is enabled, and the old diagnostics were useful, don't spit out new "you tried to use this feature but it's unstable" diagnostics that aren't helpful.

  10. RobbieMcKinstry commented on Oct 10, 2019

    @RobbieMcKinstry

    I'll take a stab at it. First time contributor, so I might not know all the hurtles, but I'll take a swing at it.

  11. Centril commented on Oct 10, 2019

    @Centril
    Contributor
  12. assigned and unassigned on Oct 10, 2019
  13. Aloso commented on Oct 13, 2019

    @Aloso
    Contributor

    Eventually however, e.g. with a follow-up RFC, I would like to turn let into a true semantic expression typed at bool such that e.g. if !let Foo::Bar = x { ... } becomes legal.

    @Centril I'm not sure if this is a good idea, because let is usually used to create variable bindings. But with let expressions, the scope of these variables can get much more complicated. Example:

    if let Some(x) = foo && !let Some(y) = bar {
        // we can access x, but not y
    } else {
        // what about this scope???
    }
  14. Centril commented on Oct 13, 2019

    @Centril
    Contributor

    @Aloso It's probably best to discuss that once an RFC is made but let's not do it here. :)

  15. jafern14 commented on Oct 28, 2019

    @jafern14

    @rustbot claim

  16. assigned and unassigned on Oct 28, 2019
  17. jafern14 commented on Oct 28, 2019

    @jafern14

    I've got the change locally now with exactly what @Centril had mentioned in a previous message. The only thing I'm getting right now is that the compiler is highlighting the entire statement and not just the let keyword like before.

    I'm looking for the method where I can get this. I'll put up a PR in a bit to show where I'm at along with some terminal output to demonstrate a bit better what I'm talking about if it doesn't make sense already.

  18. jafern14 commented on Oct 28, 2019

    @jafern14

    Opened #65893

  19. estebank commented on Oct 28, 2019

    @estebank
    Contributor

    Don't worry about the span, it is ok as it is in your pr.

  20. added a commit that references this issue on Oct 28, 2019
    30431a3
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

A-diagnosticsArea: Messages for errors, warnings, and lintsA-let-chainsArea: let chains (if-let, while-let, ...)D-confusingDiagnostics: Confusing error or lint that should be reworked.E-easyCall for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue.E-help-wantedCall for participation: Help is requested to fix this issue.E-mentorCall for participation: This issue has a mentor. Use #t-compiler/help on Zulip for discussion.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions