Skip to content

Arms permitted when matching on uninhabited types #55123

Description

@varkor

There seem to be two issues here:

pub enum Void {}

pub fn foo(x: Void) {
  match x {
    _ => {} // This arm shouldn't be permitted.
  };
  let _ = (); // This should be warned as unreachable, but isn't.
}

On the other hand, the following code does warn:

match () {
	() => {} // okay
	_ => {} // unreachable pattern
}

Activity

  1. varkor commented on Oct 16, 2018

    @varkor
    ContributorAuthor

    The second issue is a direct result of the first, where "number of arms" is treated as a heuristic for divergence, rather than the type of the expression (this could be an issue in the future with regards to an explicit ! pattern):
    https://github.com/rust-lang/rust/blob/3b88a54ebcf1d704fddd464e9d5225530cfb475b/src/librustc_typeck/check/_match.rs#L611-L615

  2. added
    A-lintsArea: Lints (warnings about flaws in source code) such as unused_mut.
    on Oct 16, 2018
  3. varkor commented on Oct 16, 2018

    @varkor
    ContributorAuthor

    This is due to:

    fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool {
    if self.tcx.features().exhaustive_patterns {
    self.tcx.is_ty_uninhabited_from(self.module, ty)
    } else {
    false
    }
    }
    I think the solution here is to stabilise exhaustive_patterns.

  4. added
    A-exhaustiveness-checkingRelating to exhaustiveness / usefulness checking of patterns
    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.
    C-bugCategory: This is a bug.
    and removed
    C-enhancementCategory: An issue proposing an enhancement or a PR with one.
    on May 22, 2020
  5. Nadrieril commented on Nov 9, 2020

    @Nadrieril
    Member

    I don't think exhaustive_patterns would fix the second issue: it would detect the arm as unreachable, but afaik that bit of match checking does not count towards counting the match as divergent.

  6. Nadrieril commented on Nov 22, 2020

    @Nadrieril
    Member

    The second issue got fixed in #78995. I'm wondering about the first one: is matching on an empty enum very different from getting a value of an empty type as input? My hunch would be that if we lint any code after match x {} to be unreachable, why not lint the whole function body after fn foo(x: Void) as unreachable? Is there a particular reason that either is more natural/useful for an user?

    pub enum Void {}
    
    pub fn foo(x: Void) {
      let _ = (); // Frankly this also could be warned as unreachable.
      match x {};
      let _ = (); // This could be warned as unreachable, but isn't.
    }
  7. varkor commented on Nov 22, 2020

    @varkor
    ContributorAuthor

    I agree that these are essentially the same issue. I actually submitted a PR a couple of years ago to address this, by making the uninhabitedness checking more eager (see #47291), but parts of it were split out to err on the side of being more conservative. I can't quite remember the status: probably in order to make these changes, there would need to be a discussion into how eagerly one wants to mark unreachable code based on uninhabited types. Probably this issue can be closed, and potentially a new one opened to explore reachability based on inhabitedness.

  8. camelid commented on Mar 20, 2021

    @camelid
    Member

    It looks like the let _xyz line isn't linted as unreachable because MIR for it is not generated (even in debug mode).

    pub enum Void {}
    
    pub fn foo(x: Void) {
      match x {
        _ => {} // This arm shouldn't be permitted.
      };
      let _xyz = (); // This should be warned as unreachable, but isn't.
    }
  9. EFanZh commented on Dec 27, 2022

    @EFanZh
    Contributor

    Not sure if related, but I encountered two surprising error:

    enum Empty {}
    
    fn foo(x: &Empty) {
        match x {} // ERROR: missing match arm.
    }
    enum Empty1 {}
    
    enum Empty2 {}
    
    fn foo(x: (Empty1, Empty2)) {
        match x {} // ERROR: missing match arm.
    }

    I have to add a _ => {} arm for the code to compile.

  10. Nadrieril commented on Jan 4, 2023

    @Nadrieril
    Member

    @EFanZh this is because in an unsafe block, you could match on a &Empty or a (Empty1, u8) without causing UB (if you're careful). Because of that we can't yet allow matching without any arms on those types.
    We want to make this possible though, but that'll take some work. More details here: #51085

  11. 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-exhaustiveness-checkingRelating to exhaustiveness / usefulness checking of patternsA-lintsArea: Lints (warnings about flaws in source code) such as unused_mut.C-bugCategory: This is a bug.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