idris-lang / Idris2

A purely functional programming language with first class types
https://idris-lang.org/
Other
2.53k stars 378 forks source link

[ fix ] Address some proofs of void via impossible from issues #2250 and #3276 #3396

Open dunhamsteve opened 1 month ago

dunhamsteve commented 1 month ago

Description

This PR addresses a few issues in #2250 and issue #3276. They are caused by an issue with IAlternative in impossible clauses, a type confusion issue in impossible clauses, and treatment of out of hidden constructors as impossible. An additional issue was brought up in #2250 that is not addressed here. I'll first discuss the issues and how I resolved them and then discuss a frex issue that should be patched before merging.

Issues fixed

The IAlternative issue is illustrated at the top of #2550:

%default total

g : Not Bool
g () impossible

f : Void
f = g True

Here the impossible clause is accepted because the type doesn't match at all, but when it is converted by mkTerm to a term for coverage checking, the ambiguous () is converted to a pattern variable which is then considered to cover everything. I addressed this by choosing the default alternative. I didn't see a way to determine the appropriate alternative at that point in the code. A user will have to explicitly say Unit or Pair to get the other option in an impossible clause.

The type confusion issue is illustrated in #2250 by:

import Data.Nat
%default total

f : n `LTE` m -> Void
f Z impossible
f (LTESucc x) = f x

x : Void
x = f $ LTEZero {right=Z}

Here Z is impossible because it has the wrong type, but during coverage checking only the constructor tag is looked at and Z is confused with LTEZero. I addressed this by also checking that the name matches. I coerce the names to resolved names in getCons because some constructor names were resolved in the context and others were not.

Finally, in #3276 there was a false impossible because a constructor was not visible. I adjusted recoverableError to not consider InvisibleName to be evidence of impossible.

The issues fixed in #2250 and #3276 are included as test cases.

Frex

Frex is relying on the ambiguity bug with Pair/MkPair in one location. The function is indeed covering, but Idris cannot capable of determining that if MkPair is used instead of (,). The current code is only working because of the above bug. This can be addressed with the following patch to frex, which pushes the impossible match down to a separate case tree:

diff --git a/src/Frexlet/Monoid/Frex/Structure.idr b/src/Frexlet/Monoid/Frex/Structure.idr
index 8ccc22e..0164d67 100644
--- a/src/Frexlet/Monoid/Frex/Structure.idr
+++ b/src/Frexlet/Monoid/Frex/Structure.idr
@@ -159,8 +159,10 @@ MultHomomorphism a s (i, ConsUlt i1 x is) (j,ConsUlt j1 y js)
   = ( a.cong 2 (Dyn 0 .*. Dyn 1) [_,_] [_,_] [i_eq_j, i1_eq_i2]
     , x_eq_y
     ) :: is_eq_js
-MultHomomorphism _ _ (_, Ultimate _) (_, ConsUlt _ _ _) (MkAnd _ _) impossible
-MultHomomorphism _ _ (_, ConsUlt _ _ _) (_, Ultimate _) (MkAnd _ _) impossible
+MultHomomorphism _ _ (_, Ultimate _) (_, ConsUlt _ _ _) x with (x)
+  _ | MkAnd _ _ impossible
+MultHomomorphism _ _ (_, ConsUlt _ _ _) (_, Ultimate _) x with (x)
+  _ | MkAnd _ _ impossible

 public export
 AppendHomomorphismProperty : (a : Monoid) -> (x : Setoid) ->
andrevidela commented 2 weeks ago

@mjustus I think this is waiting on you to approve, right?