Skip to content
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 guards give false exhaustivity errors #2795

Closed
paf31 opened this issue Mar 30, 2017 · 7 comments
Closed

Pattern guards give false exhaustivity errors #2795

paf31 opened this issue Mar 30, 2017 · 7 comments

Comments

@paf31
Copy link
Contributor

paf31 commented Mar 30, 2017

Example:

module Main where

import Prelude

data X = X Int | Y

x :: X -> Int
x = case _ of
      Y -> 0
      X n | 1 <- n -> 1
          | otherwise -> 2

which gives:

Error found:
in module Main
at src/Main.purs line 9, column 5 - line 12, column 26

  A case expression could not be determined to cover all inputs.
  The following additional cases are required to cover all inputs:

    Y

  Alternatively, add a Partial constraint to the type of the enclosing value.

while applying a function __unused
  of type Partial => t0 -> t0
  to argument case $0 of              
                (X n) | otherwise -> 2
while inferring the type of __unused (case $0 of              
                                        (X n) | otherwise -> 2
                                     )                        
in value declaration x

where t0 is an unknown type

It looks like the desugaring is at fault here, since X n is the only alternative left after things are expanded.

@alexbiehl Any ideas here?

@paf31 paf31 added this to the 0.11 milestone Mar 30, 2017
@alexbiehl
Copy link
Contributor

x is transformed into

x :: X -> Int 
x y = case y of 
    Y -> 0 
    _ -> let 
           k _ = case y of 
                 X n | otherwise -> 2
          in case y of 
            X n -> case n of -- guard 1 <- n
                1 -> 1
                _ -> k true 

We scrutinize y multiple times here but only bind to X n, missing Y in those cases.

@alexbiehl
Copy link
Contributor

alexbiehl commented Mar 30, 2017

Lets see if I can come up with something better.

btw. I know its a bad excuse but in this example you can change the order of matches to:

x :: X -> Int
x = case _ of
      X n | 1 <- n -> 1
          | otherwise -> 2
      Y -> 0

and it works.

@alexbiehl
Copy link
Contributor

I think the transformation is right, the exhaustivity checker just doesn't know that in subsequent matches missing cases can be ruled out.

We have different alternatives I guess:

  • Remember what constructors we already matched and generate "unreached" alternatives. I think we lack a notion of "unreached" alternative and I am not sure we want such thing. We can't just use wildcard binders alone as that would result false-exhaustive cases which is even worse.
  • Just don't desugar cases before exhaustivity checking. Desugar them in the ps2core pass instead. I had the part for type checking and exhaustivity around when developing the original feature so this should be no big deal.

btw. Are there any written down notes on invariants of case expressions in surface language?

@paf31
Copy link
Contributor Author

paf31 commented Mar 30, 2017

Thanks for looking at this.

If it's possible to move the transformation after linting and/or type-checking, I think that would be the way to go.

@matthewleon
Copy link
Contributor

matthewleon commented Apr 3, 2017

I am still having this problem on 0.11.2.

Code:

head :: forall a. Stream a -> a
head xs | Cons x _ <- step xs = x

error:

in module Main
at src/Main.purs line 35, column 1 - line 35, column 33

  A case expression could not be determined to cover all inputs.
  The following additional cases are required to cover all inputs:

    _

  Alternatively, add a Partial constraint to the type of the enclosing value.

while applying a function __unused
  of type Partial => t1 -> t1
  to argument case xs of                     
                xs | Cons x _ <- step xs -> x
while checking that expression __unused (case xs of                     
                                           xs | Cons x _ <- step xs -> x
                                        )                               
  has type a0
in value declaration head

where a0 is a rigid type variable
        bound at line 35, column 1 - line 35, column 33
      t1 is an unknown type

@alexbiehl
Copy link
Contributor

alexbiehl commented Apr 3, 2017 via email

@paf31
Copy link
Contributor Author

paf31 commented Apr 3, 2017

Let's open a new issue for this one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants