Locally reified GADT record selectors have incorrect types
RyanGlScott opened this issue · comments
Run this program:
#!/usr/bin/env cabal
{- cabal:
build-depends: base, pretty-show, template-haskell, th-desugar >= 1.9
-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
module Main where
import Language.Haskell.TH
import Language.Haskell.TH.Desugar
import Text.Show.Pretty
main :: IO ()
main = putStrLn
$([d| data T :: * -> * where
MkT :: forall a. { unT :: a } -> T a
|] >>= \ds -> withLocalDeclarations ds (dsReify (mkName "unT")) >>= stringE . ppShow)
And you'll get this:
$ cabal new-run Bug.hs
Resolving dependencies...
Build profile: -w ghc-8.6.3 -O1
<elided>
Just
(DVarI
unT
(DAppT
(DAppT DArrowT (DConT T_6989586621679053292))
(DVarT a_6989586621679053295))
Nothing)
After some cleanup, that's:
unT :: T -> a
That type is utterly bogus, as it should be:
unT :: forall a. T a -> a
Here's a similar example:
main :: IO ()
main = putStrLn
$([d| data T b where
MkT :: forall a. { unT :: a } -> T a
|] >>= \ds -> withLocalDeclarations ds (dsReify (mkName "unT")) >>= stringE . ppShow)
$ cabal new-run Bug.hs
Resolving dependencies...
Build profile: -w ghc-8.6.3 -O1
<elided>
Just
(DVarI
unT
(DForallT
[ DPlainTV b_6989586621679053293 ]
[]
(DAppT
(DAppT
DArrowT
(DAppT
(DConT T_6989586621679053290) (DVarT b_6989586621679053293)))
(DVarT a_6989586621679053294)))
Nothing)
unT :: forall b. T b -> a
The reason this happens is because of this part of Language.Haskell.TH.Desugar.Reify
:
th-desugar/Language/Haskell/TH/Desugar/Reify.hs
Lines 267 to 269 in 89adebd
We're grabbing the arguments to the data type constructor from the head of the GADT, but this is a dangerous thing to do, since there might not be enough arguments entirely (as in the data T :: * -> *
case) or they may have different names (as in the data T b
case).
The plot thickens. This bug also affects GADT constructors without record selectors, as in the following example:
{-# LANGUAGE TemplateHaskell #-}
module Main where
import Language.Haskell.TH
import Language.Haskell.TH.Desugar
main :: IO ()
main = putStrLn
$([d| data T a where
MkT :: Int -> T Int
|] >>= \ds -> withLocalDeclarations ds (reifyWithLocals (mkName "MkT")) >>= stringE . pprint)
Constructor from T_0: MkT :: forall a_1 .
GHC.Types.Int -> T_0 GHC.Types.Int
That forall a_1
shouldn't be there.