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

restrictCoRec is unsound #171

Open
samuel-gelineau-at-well-dot opened this issue Sep 20, 2023 · 1 comment
Open

restrictCoRec is unsound #171

samuel-gelineau-at-well-dot opened this issue Sep 20, 2023 · 1 comment

Comments

@samuel-gelineau-at-well-dot

The following fails with Exception: matchNil: impossible

  let intOrString :: CoRec Identity '[Int, String]
      intOrString = CoRec (Identity "hello")
  case restrictCoRec intOrString of
    Left (Identity int) -> do
      print int
    Right definitelyString -> do
      case restrictCoRec (definitelyString :: CoRec Identity '[String]) of
        Left (Identity string) -> print string
        Right uninhabited -> matchNil (uninhabited :: CoRec Identity '[])

Workaround: use restrictCoRecSafe instead of restrictCoRec.

@samuel-gelineau-at-well-dot
Copy link
Author

samuel-gelineau-at-well-dot commented Sep 20, 2023

Let's look at the relevant definitions:

data CoRec :: (k -> *) -> [k] -> * where
  CoRec :: RElem a ts (RIndex a ts) => !(f a) -> CoRec f ts

restrictCoRec :: ... => CoRec f (t ': ts) -> Either (f t) (CoRec f ts)
restrictCoRec r = maybe (Right (unsafeCoerce r)) Left ...

I think the problem is that in the Nothing case, unsafeCoerce r does more than just reinterpreting CoRec fa :: CoRec f (t ': ts) into CoRec fa :: CoRec f ts, it also reinterprets the RElem dictionary.

Thus:

  1. We start with a CoRec Identity [Int, String] containing a valid proof that String is in the second position in the list [Int, String].
  2. The proof says that String is not in the first position, so the first restrictCoRec call casts this into a CoRec Identity [String] containing an invalid proof that String is in the second position in the list [String].
  3. The invalid proof still says that String is not in the first position, so the second restrictCoRec call casts this into a CoRec Identity [] containing an invalid proof that String is in the second position in the list [].
  4. Finally, matchNil errors out because it assumes that CoRec Identity '[] should be uninhabited, since it is not possible to construct a proof that String appears in the list []. But here, we have managed to construct a non-standard inhabitant by using unsafeCoerce to construct an invalid proof.

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

No branches or pull requests

1 participant