-
Notifications
You must be signed in to change notification settings - Fork 434
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 alternative binding empty type does not cause redundant alternative warning #4110
Comments
Thanks for your report. I believe the current behavior is correct: for Note that If you are unsure about this I suggest you bring this up on the community Zulip. |
This is what I was saying! The following is considered a hard error in lean: third case is considered redundant
In this code, however, I can add or remove last pattern at will.
Did I actually fail to convey this? 👀 |
Ah, yes, I think I misunderstood your issue indeed. Sorry! I think you are right that there is something unexpecting about leans behavior here. I guess the current implementation has its reasons. After all, it's ok to bind But I agree that it's reasonable to expect that an alternative that can be omitted is warned about, and we can keep this issue for it. |
I took the library of tweaking the issue description and title a bit. Thanks for your report! |
I agree that this is confusing. There is a fundamental issue here. In general, we cannot decide whether a pattern is redundant - I can define a type whose constructor is a witness of the truth of the Collatz conjecture, for instance. This means that checking pattern coverage is, at the end of the day, an approximation. When the user omits a pattern for a given constructor, our task is to try to prove that this constructor was impossible. Here, we want an under-approximation - it's OK to make a user write a proof that a case was impossible, but we can't accept Lean missing a case that actually is possible. The elaboration to eliminators checks our work here. When a user does write a pattern for a constructor, we want an over-approximation. It'd be terrible to prevent the use of a constructor that's actually possible, but it's not the end of the world to allow a provably superfluous but otherwise type-correct constructor that the user then must write a manual proof about. I'd characterize this issue as Lean not preventing you from manually writing a proof that it could otherwise build automatically, but the UI certainly doesn't make it clear that this is what's going on. We're in the realm of two undecidable analyses meeting in a gray area. It's good for them to agree often, especially in simply-typed cases like this one, but perfection is unachievable. |
Right! But why unachievable? In the example above lean is perfectly happy if you omit the case, so it is able to determine that the case wasn't needed! So, superficially, why can't it use whatever logic is at work to warn the user about it? My (blind) guess is that when the user omits a clause lean tries harder to prove that this is ok (maybe using |
Perfection is unachievable here, but we could absolutely give better errors/warnings/lints for this particular situation, as well as many related ones. No question about that! |
Sorry, what I meant was: perfection of recognizing unreachable branches is of course unachievable. But showing a warning exactly about those branches that you could omit without lean complaining is certainly achievable, isn't it? |
I think there are good reasons to preserve the current lean behavior. If you have a macro that generates def foo : Option $type -> Nat
| none => 0
| some x => 1 it should not suddenly become a type error if we substitute That said, it would be reasonable to have a linter that points out when a given pattern can safely be removed because it is refutable by lean, although it may be expensive. |
Interesting, “redundant alternative” is actually an error, not a warning (which could be turned off for generated code) as I expected. I guess warnings and linters are not that difficult. Anyways, even if there is something that can be improved here, it's probably not pressing. We can keep the issue to refer to should this come up again |
I'd like to point out this can also arise without an empty type, if certain branches are known by Lean to be impossible: inductive T (n: Nat)
| a (_: n = 3)
| b (_: n = 4)
def T.foo (t: T 3): True :=
match t with
| a _ => trivial -- accepted
def T.fooUnnecessary (t: T 3): True :=
match t with
| a _ => trivial
| b _ => trivial -- accepted, but redundant At least in my experience, it has happened in practice that such a warning would have saved me time as a user, because I did not always realize Lean could automatically handle an impossible branch for me. |
So, lean has coverage checking in pattern-matching, e.g. this code...
...does not get accepted and missing case is reported. Good!
Lets now consider a slightly different definition:
This one is considered correct by lean, no errors about missing cases are reported.
However, if I add another pattern to this definition...
...it still gets accepted without a warning. The redundant pattern is not reported as such!
This means that matches on empty types are redundant, but the helpful warning does not appear.
It would be helpful if it would, if possible.
The text was updated successfully, but these errors were encountered: