Skip to content

Derived Read instance of record containing phantom type is incorrect

Summary

Given a phantom type with custom read/show instances, when wrapped inside a record, the derived read instance is incorrect.

Steps to reproduce

Given the following code:

{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE DataKinds #-}

import GHC.TypeLits
import Text.Read
import Text.ParserCombinators.ReadP (string)
import Data.Proxy

data Phantom (a :: Symbol) = Single

instance forall s. KnownSymbol s => Show (Phantom s) where
  show Single = symbolVal (Proxy @s)

instance KnownSymbol s => Read (Phantom s) where
  readPrec = readP_to_Prec $ \_ -> string (show $ Single @s) >> pure Single

newtype Foo = Foo { f :: Phantom "casper" } deriving (Show, Read)

main = do
  print (read "casper" :: Phantom "casper")
  print (Foo Single)
  print (read "Foo {f = casper}" :: Foo)

Running this code produces an exception:

$ runhaskell bug.hs
casper
Foo {f = casper}
Foo {f = bug.hs: Prelude.read: no parse

Expected behavior

This code should not crash.

Environment

  • GHC version used: 9.0.2.

Optional:

  • Operating System: NixOS 22.11.20220604.231efec (Raccoon)
  • System Architecture: x86_64 GNU/Linux
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information