Skip to content

Irrefutable if let on a single-variant enum only produces () value #61788

Closed

Description

@moxian

The following code (playground)

enum Enum{
    Variant(i32),
}

fn stuff(x: Enum) -> i32{
    if let Enum::Variant(value) = x {
        value
    }
}

gives the following error:

   Compiling playground v0.0.1 (/playground)
error[E0317]: if may be missing an else clause
 --> src/lib.rs:6:5
  |
6 | /     if let Enum::Variant(value) = x {
7 | |         value
8 | |     }
  | |_____^ expected (), found i32
  |
  = note: expected type `()`
             found type `i32`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0317`.
error: Could not compile `playground`.

which is weird, since the else clause would never be visited even if it was present.

The equivalent one-arm match

enum Enum{
    Variant(i32),
}

fn stuff(x: Enum) -> i32{
    match x {
        Enum::Variant(value) => value,
    }
}

compiles just fine (expectedly).

Adding an else { unreachable!() } branch to the if let is, of course, possible, but unelegant, and really shouldn't be needed, as it can be inferred at compile time.

Activity

  1. varkor commented on Jun 12, 2019

    @varkor
    Contributor

    You can match irrefutably without if in this case:

    fn stuff(x: Enum) -> i32 {
        let Enum::Variant(value) = x;
        value
    }

    though maybe we should give this special diagnostics.

  2. Centril commented on Jun 12, 2019

    @Centril
    Contributor

    I think this is too niche to deserve a special diagnostics (and I don't think we should substantially work on diagnostics for if until let_chains is implemented).

    which is weird, since the else clause would never be visited even if it was present.

    if let is defined by a desugaring:

    if let PAT = EXPR BLOCK_IF [else BLOCK_ELSE]

    becomes:

    match EXPR {
        PAT => BLOCK_IF,
        _ => [ {} | BLOCK_ELSE ],
    }

    so what you really wrote is:

    match x {
        Enum::Variant(value) => value,
        _ => {},
    }

    The block {} is typed at () which does not unify with value unless it is also typed at ().

  3. added
    A-diagnosticsArea: Messages for errors, warnings, and lints
    P-lowLow priority
    on Jun 13, 2019
  4. moxian commented on Jun 14, 2019

    @moxian
    ContributorAuthor

    I didn't know let Enum::Variant(value) = x; was a valid syntax. If I did, I probably wouldn't have filed the issue, because of course, in hindsight, that's how you write an infallible if let.

    (With that knowledge in mind) I agree that it's only a diagnostics issue and no language change is needed here.
    And I fully agree that it's a niche low-priority quirk that should maybe be fixed "someday". (I don't know what let_chains but even then I'd guess that this one is lower priority than that).

  5. added
    A-lintsArea: Lints (warnings about flaws in source code) such as unused_mut.
    on Jul 25, 2019
  6. estebank commented on Jul 25, 2019

    @estebank
    Contributor

    I think the appropriate thing to do here would be to lint on if let Irrefutable = foo {}, which would have clarified things.

  7. estebank commented on Jul 25, 2019

    @estebank
    Contributor

    But we do only after typechecking, and we don't if there are any errors before then. Quite a few lints have similar issues related to not happening early enough.

  8. Centril commented on Jul 25, 2019

    @Centril
    Contributor

    @estebank How do you know that the pattern is irrefutable before match checking in HAIR?

  9. estebank commented on Jul 25, 2019

    @estebank
    Contributor

    You can't, but you can write the lint in such a way that it triggers regardless. We're getting to typechecking, we should be able to detect irrefutability by then. It just can't use the standard linting machinery (like a few other lints already do to avoid being silenced by accident).

  10. added
    C-enhancementCategory: An issue proposing an enhancement or a PR with one.
    T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
    on Nov 27, 2019
  11. added 2 commits that reference this issue on Jan 29, 2024
    f9b5eb1
    51a090b
  12. added a commit that references this issue on Feb 6, 2024
    a939bad
  13. added 2 commits that reference this issue on Feb 7, 2024
    0aefc20
    cc7edbc
  14. added a commit that references this issue on Feb 7, 2024
    a77a2a8
  15. added
    A-lintsArea: Lints (warnings about flaws in source code) such as unused_mut.
    and removed
    A-lintsArea: Lints (warnings about flaws in source code) such as unused_mut.
    on Dec 21, 2024
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 lintsA-lintsArea: Lints (warnings about flaws in source code) such as unused_mut.A-suggestion-diagnosticsArea: Suggestions generated by the compiler applied by `cargo fix`C-enhancementCategory: An issue proposing an enhancement or a PR with one.P-lowLow priorityT-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