-
Notifications
You must be signed in to change notification settings - Fork 12.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Pattern reachability algorithm fails in the presence of uninhabited types #12609
Comments
cc @brson @nikomatsakis @pcwalton (not really sure who I should be cc-ing): I think this is a backwards compatibility issue in the respect that fixing this bug will cause fewer programs to be accepted. We should make it clear that pattern matching uninhabited types with wildcard patterns is not legal according to the language spec, that it being currently accepted is a compiler bug, and that we reserve the right to fix the bug in the future (if/when we figure out how to). See examples above if the rationale isn't clear. |
Well, if anything, this would require extending the definition of an empty type to include sum types with all members being empty and product types with at least one empty operand. |
Yes, this is implied by the term "uninhabited type". (Or do you mean that there's a definition of an "empty type" in some official spec that needs updating?) |
I agree with @glaebhoerl, though this is clearly a corner case. I wonder if we should remove disallow uninhabited enums and make our lives easier? |
/me cannot help but point at #4499 (comment) (though arguably feature-gating is quite different from outright removal...) |
Nominating, P-backcompat-lang. See #12609 (comment) for the basis. |
Assigning P-backcompat-lang, 1.0 milestone. (There are many interesting ways to resolve this, and some not-so-interesting ways.) |
Uninhabited enums are useful as phantom type parameters. |
OCaml has the same behavior as Rust today:
|
SML/NJ ICE's:
|
@pcwalton that's hilarious |
I was going to try Scala and Haskell but there is no such thing as an uninhabited type in Scala because of Given this exciting romp through languages, I'm going to vote that we go with the only other working compiler that handles this case, and close this as not a bug. Nominating for closure. |
Why is that preferable to saying that it is a bug that we may, at our option, fix in the future? I mean, we can even change our minds later if we convince ourselves that it's impossible. But not vice versa. |
GHC does check exhaustiveness but it produces a warning. And it indeed doesn't handle this properly: import Unsafe.Coerce
data Void
f :: Maybe Void -> Int
f Nothing = 0
main :: IO ()
main = putStr . show . f . unsafeCoerce $ 0 complains with:
|
@jakub- Only when you compile with |
This survey of other languages is very interesting, but I don't see why it's very relevant. The correct behavior is not in question. Just because other implementations also have the bug, that doesn't mean it's not a bug. |
@pcwalton I'd rather feature-guard uninhabited enums than commit forever (or at least for 1.x) to our current implementation of how they are handled in |
As a middle ground: would it be reasonable to just feature gate |
@huonw depending on how one interprets "whenever |x: Option<Uninhabited>| match x { ... } is caught by the net.) |
@pnkfelix Feature-gating uninhabited enums will not be sufficient as the same problem applies to !.
I think feature gating |
@jakub- I do not think In the example you gave, bottom is unified with If you revise your example to avoid unifying |
Right, thanks! In that case, I don't have a strong opinion other than that
|
To pose the question once more: It's safe to assume that the 1.0 compiler will have bugs. I hope it's also safe to assume that we won't hesitate to fix those bugs, even if doing so has the side effect of breaking programs which relied on the buggy behavior. Why isn't the easiest and most appropriate solution to simply note that this is a bug, and move on? We don't have to fix it before 1.0. We don't have to fix it next year. All we have to do is to say that it's a bug. |
Following similar reasoning to what @glaebhoerl presented above: We are not going to block 1.0 on resolving this issue. It is a P-backcompat-lang issue, but it is one that we feel prepared to handle (or explicitly not handle, i.e. leave things as they are), post 1.0, in some manner. P-backcompat-lang, not 1.0 milestone. |
Lang team discussed, and we don't feel that this is a very serious issue -- in particular, this only comes up when matching against an empty type, which is very rare to begin with, and the lack of exhaustiveness checking there is unlikely to hide any serious bugs. P-low. |
Not just matching directly on an empty (uninhabited) type, but also on a composite type involving one. In particular types like (Not disputing the priority, which I have no opinion on, only the characterization.) |
@glaebhoerl Yes, my summary was a little too brief -- the match against an empty type could occur in the context of another type. It is a good point that the introduction of |
I think this should be fixed before |
Some concrete motivation for that: for user-defined uninhabited |
@canndrew I added this as a note to the |
I've had a crack at implementing this here: #36476 Also, the change I've implemented allows people to omit patterns that are unreachable due to uninhabited types but doesn't force them to. This is important for backwards-compatibility but also because I think code like this: let res: Result<T, E> = ...;
match res {
Ok(t) => ...,
Err(e) => ...,
} should be allowed to compile even when |
This alters the exhaustiveness-checking algorithm for pattern matches to avoid raising spurious errors about cases not being covered for uninhabited types. Specifically, the construct_witness function now returns an Option. If it sees that DUMMY_WILD_PAT is being used to match on an uninhabited type it returns None to indicate that there is no witness. We look for DUMMY_WILD_PAT specifically and not any wildcard pattern so that wildcard patterns explicitly written by the programmer continue to work without raising errors about unreachability.
Fix handling of empty types in patterns. Fix for #12609.
So should this be closed, or do we wait for it to hit stable? |
We can close. |
…age, r=Jarcho Reword `arc_with_non_send_sync` note and help messages Addresses rust-lang/rust-clippy#12608 (comment) Makes the note more concise and reframes the `Rc` suggestion around whether it crosses threads currently due to a manual `Send`/`Sync` impl or may do in the future changelog: none
From
check_match.rs
:This results in, most prominently (#4499), a
match
on an empty enum with a wildcard pattern being accepted:while if you add a variant to the enum and a corresponding arm to the match:
rustc rejects the program with
error: unreachable pattern
.Clearly a trailing wildcard pattern after you've already matched all possible values in preceding arms should always be considered unreachable, and this is true even when the number of potential values, and hence preceding arms, are both zero.
As the comment notes the algorithm we use relies on "no empty types" as an assumption, so this may not be an easy bug, but it's still a bug.
The text was updated successfully, but these errors were encountered: