Skip to content

Missing trailing expression in block with let else yields incorrectly spanned error message #94176

Closed

Description

@JakobDegen

I tried this code:

#![feature(let_else)]

pub fn test(a: Option<u32>) -> Option<u32> {
    let Some(_) = a else { return None; };
    println!("Foo");
}

fn main() {}

I expected to see this happen: A helpful error message pointing to the end of the block.

Instead, this happened: An error message with a wrong span:

error[E0308]: mismatched types
 --> test.rs:4:5
  |
4 |     let Some(_) = a else { return None; };
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `Option`, found `()`
  |
  = note:   expected enum `Option<u32>`
          found unit type `()`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.

Meta

rustc --version --verbose:

rustc 1.60.0-nightly (b17226fcc 2022-02-18)
binary: rustc
commit-hash: b17226fcc11587fed612631be372a5b4cb89988a
commit-date: 2022-02-18
host: x86_64-unknown-linux-gnu
release: 1.60.0-nightly
LLVM version: 14.0.0

cc #87335

@rustbot labels: +T-compiler +F-let-else +requires-nightly +A-diagnostics

Activity

  1. JakobDegen commented on Feb 20, 2022

    @JakobDegen
    ContributorAuthor

    Let's try that again...

    @rustbot label +T-compiler +F-let-else +requires-nightly +A-diagnostics

  2. added
    A-diagnosticsArea: Messages for errors, warnings, and lints
    F-let_elseIssues related to let-else statements (RFC 3137)
    requires-nightlyThis issue requires a nightly compiler in some way. When possible, use a F-* label instead.
    T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
    on Feb 20, 2022
  3. est31 commented on Feb 20, 2022

    @est31
    Member

    FTR this is the error for the if let equivalent:

    pub fn test(a: Option<u32>) -> Option<u32> {
        if let Some(_) = a {
        } else {
            return None;
        }
        println!("Foo");
    }
    error[E0308]: mismatched types
     --> src/main.rs:3:32
      |
    3 | pub fn test(a: Option<u32>) -> Option<u32> {
      |        ----                    ^^^^^^^^^^^ expected enum `Option`, found `()`
      |        |
      |        implicitly returns `()` as its body has no tail or `return` expression
      |
      = note:   expected enum `Option<u32>`
              found unit type `()`
    
  4. est31 commented on Feb 20, 2022

    @est31
    Member

    I wonder how #94012 is affecting this, as this seems to be a bug in the desugaring and that PR changes it. @cormacrelf what is the error output with your PR applied? Does it fix the issue? If so, maybe adding a test to your PR would be helpful.

  5. est31 commented on Feb 20, 2022

    @est31
    Member

    I meant caused by the desugaring, not in the desugaring.

  6. cormacrelf commented on Feb 20, 2022

    @cormacrelf
    Contributor

    It won't fix it. This needs a bit of work I think, to push the error further inside the if-let-else branch, so the span marked is the implicit return expression or lack thereof, which is (in the source code) further down in the block.

  7. est31 commented on Feb 20, 2022

    @est31
    Member

    Hmm if you move the println into the if let, it gives a similar error to the one emitted by let else:

    pub fn test(a: Option<u32>) -> Option<u32> {
        if let Some(_) = a {
            println!("Foo");
        } else {
            return None;
        }
    }

    gives

    error[E0308]: mismatched types
     --> src/main.rs:2:24
      |
    2 |       if let Some(_) = a {
      |  ________________________^
    3 | |         println!("Foo");
    4 | |     } else {
      | |_____^ expected enum `Option`, found `()`
      |
      = note:   expected enum `Option<u32>`
              found unit type `()`
    
  8. cormacrelf commented on Feb 21, 2022

    @cormacrelf
    Contributor

    That's because you have only now reproduced the actual desugaring.

  9. cormacrelf commented on Feb 21, 2022

    @cormacrelf
    Contributor

    I'm starting to think the nested desugaring is not such a good idea. Even the guy who implemented it forgot how it worked the other day, it continues to mystify, and now we have some more error message complications. It's less work in hir lowering, but has absolutely no other benefits.

  10. added a commit that references this issue on Aug 12, 2022
  11. added a commit that references this issue on Sep 16, 2022
  12. added a commit that references this issue on Sep 17, 2022
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-diagnosticsArea: Messages for errors, warnings, and lintsC-bugCategory: This is a bug.F-let_elseIssues related to let-else statements (RFC 3137)T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.requires-nightlyThis issue requires a nightly compiler in some way. When possible, use a F-* label instead.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions