Skip to content
GitLab
Projects Groups Snippets
  • /
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
  • Sign in / Register
  • GHC GHC
  • Project information
    • Project information
    • Activity
    • Labels
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
    • Locked Files
  • Issues 5,246
    • Issues 5,246
    • List
    • Boards
    • Service Desk
    • Milestones
    • Iterations
  • Merge requests 564
    • Merge requests 564
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
    • Test Cases
  • Deployments
    • Deployments
    • Releases
  • Analytics
    • Analytics
    • Value stream
    • CI/CD
    • Code review
    • Insights
    • Issue
    • Repository
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • Glasgow Haskell CompilerGlasgow Haskell Compiler
  • GHCGHC
  • Issues
  • #17021
Closed
Open
Issue created Aug 03, 2019 by Ryan Scott@RyanGlScottMaintainer

Using type families in data types' return kinds leads to GHC panics and Core Lint errors

Despite #16821 (closed) being fixed, it is still possible to use type families in the return kinds of data types if UnliftedNewtypes is enabled. Moreover, GHC appears to be ill equipped to handle this, as this allows one to construct programs that fail -dcore-lint. Here is one example involving a newtype:

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UnliftedNewtypes #-}
module Bug where

import Data.Kind
import GHC.Exts

type family Id (x :: a) :: a where
  Id x = x

newtype T :: TYPE (Id LiftedRep) where
  MkT :: Int -> T

f :: T
f = MkT 42

Click below to see the Core Lint error you get when compiling it:

$ ~/Software/ghc3/inplace/bin/ghc-stage2 Bug.hs -dcore-lint
[1 of 1] Compiling Bug              ( Bug.hs, Bug.o )
*** Core Lint errors : in result of Desugar (after optimization) ***
Bug.hs:18:1: warning:
    [RHS of f :: (T |> (TYPE
                          (D:R:Id[0] <RuntimeRep>_N <'LiftedRep>_N))_N)]
    The type of this binder doesn't match the type of its RHS: f
    Binder's type: (T |> (TYPE
                            (D:R:Id[0] <RuntimeRep>_N <'LiftedRep>_N))_N)
    Rhs type: T
*** Offending Program ***
f :: (T |> (TYPE (D:R:Id[0] <RuntimeRep>_N <'LiftedRep>_N))_N)
[LclIdX]
f = (I# 42#) `cast` (Sym (N:T[0]) :: Int ~R# T)

$trModule :: Module
[LclIdX]
$trModule = Module (TrNameS "main"#) (TrNameS "Bug"#)

*** End of Offense ***


<no location info>: error: 
Compilation had errors

And here is another involving a data family:

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UnliftedNewtypes #-}
module Bug where

import Data.Kind
import GHC.Exts

type family Id (x :: a) :: a where
  Id x = x

data family T :: TYPE (Id LiftedRep)
newtype instance T where
  MkT :: Int -> T

f :: T
f = MkT 42
$ ~/Software/ghc3/inplace/bin/ghc-stage2 Bug.hs -dcore-lint
[1 of 1] Compiling Bug              ( Bug.hs, Bug.o )
*** Core Lint errors : in result of Simplifier ***
Bug.hs:19:1: warning:
    [RHS of f :: (T |> (TYPE
                          (D:R:Id[0] <RuntimeRep>_N <'LiftedRep>_N))_N)]
    The type of this binder doesn't match the type of its RHS: f
    Binder's type: (T |> (TYPE
                            (D:R:Id[0] <RuntimeRep>_N <'LiftedRep>_N))_N)
    Rhs type: T
*** Offending Program ***
f_s122 :: Int
[LclId,
 Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,
         WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 10 20}]
f_s122 = I# 42#

f :: (T |> (TYPE (D:R:Id[0] <RuntimeRep>_N <'LiftedRep>_N))_N)
[LclIdX,
 Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,
         WorkFree=True, Expandable=True,
         Guidance=ALWAYS_IF(arity=0,unsat_ok=True,boring_ok=True)}]
f = f_s122 `cast` (Sym (N:R:T[0]) ; Sym (D:R:T0[0]) :: Int ~R# T)

$trModule_s123 :: Addr#
[LclId,
 Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,
         WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 20 0}]
$trModule_s123 = "main"#

$trModule_s124 :: TrName
[LclId,
 Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,
         WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 10 20}]
$trModule_s124 = TrNameS $trModule_s123

$trModule_s125 :: Addr#
[LclId,
 Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,
         WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 20 0}]
$trModule_s125 = "Bug"#

$trModule_s126 :: TrName
[LclId,
 Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,
         WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 10 20}]
$trModule_s126 = TrNameS $trModule_s125

$trModule :: Module
[LclIdX,
 Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,
         WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 10 30}]
$trModule = Module $trModule_s124 $trModule_s126

*** End of Offense ***


<no location info>: error: 
Compilation had errors

That's not all. If you pick a slightly different example, you can actually get GHC to panic. Here is one such example:

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UnliftedNewtypes #-}
module Bug where

import Data.Kind
import GHC.Exts

type family Id (x :: a) :: a where
  Id x = x

data family T :: TYPE (Id LiftedRep)
newtype instance T = MkT Int

f :: Int -> T
f = MkT
$ ~/Software/ghc3/inplace/bin/ghc-stage2 Bug.hs
[1 of 1] Compiling Bug              ( Bug.hs, Bug.o )
ghc-stage2: panic! (the 'impossible' happened)
  (GHC version 8.9.0.20190802:
        runtimeRepPrimRep
  typePrimRep ((Int |> (TYPE
                          (Sym (D:R:Id[0] <RuntimeRep>_N <'LiftedRep>_N)))_N) :: TYPE
                                                                                   (Id 'LiftedRep))
  Id 'LiftedRep
  Call stack:
      CallStack (from HasCallStack):
        callStackDoc, called at compiler/utils/Outputable.hs:1179:37 in ghc:Outputable
        pprPanic, called at compiler/simplStg/RepType.hs:525:5 in ghc:RepType

The culprit is the fact that TcHsType.checkDataKindSig, which is supposed to ensure that the return kind of a data type/data family declaration is well formed, only invokes tcIsRuntimeTypeKind:

    is_TYPE :: Bool
    is_TYPE = tcIsRuntimeTypeKind kind

This only checks that the return kind is of the shape TYPE r, but it does not check that r is free of type families.


You might wonder if simply disallowing the use of type families in data type return kinds would suffice to catch this bug. In other words, make the following change:

-    is_TYPE = tcIsRuntimeTypeKind kind
+    is_TYPE = tcIsRuntimeTypeKind kind && isTyFamFree kind

Unfortunately, things are not that simple. If this change is made, this causes the UnliftedNewtypesDifficultUnification test case (which is supposed to compile) to fail. This is because this test case contains the following declarations:

type family Interpret (x :: Color) :: RuntimeRep where
  Interpret 'Red = 'IntRep
  Interpret 'Blue = 'WordRep

data family Foo (x :: Color) :: TYPE (Interpret x)
newtype instance Foo 'Red = FooRedC Int#

data family Bar (x :: Color) :: TYPE (Interpret x)
newtype instance Bar 'Red :: TYPE (Lower Int) where
  MkBR :: Int# -> Bar 'Red

The fact that this test case ever worked to begin with might be an accident, since if you make a small tweak to it:

diff --git a/testsuite/tests/typecheck/should_compile/UnliftedNewtypesDifficultUnification.hs b/testsuite/tests/typecheck/should_compile/UnliftedNewtypesDifficultUnification.hs
index de831f9200..121c5515d2 100644
--- a/testsuite/tests/typecheck/should_compile/UnliftedNewtypesDifficultUnification.hs
+++ b/testsuite/tests/typecheck/should_compile/UnliftedNewtypesDifficultUnification.hs
@@ -18,6 +18,8 @@ type family Interpret (x :: Color) :: RuntimeRep where
 
 data family Foo (x :: Color) :: TYPE (Interpret x)
 newtype instance Foo 'Red = FooRedC Int#
+fooRedC :: Int# -> Foo Red
+fooRedC = FooRedC
 
 newtype Quux :: TYPE (Interpret Red) where
   MkQ :: Int# -> Quux

Then it begins to panic as described above:

$ ~/Software/ghc3/inplace/bin/ghc-stage2 UnliftedNewtypesDifficultUnification.hs
[1 of 1] Compiling UnliftedNewtypesDifficultUnification ( UnliftedNewtypesDifficultUnification.hs, UnliftedNewtypesDifficultUnification.o )
ghc-stage2: panic! (the 'impossible' happened)
  (GHC version 8.9.0.20190802:
        runtimeRepPrimRep
  typePrimRep ((Int# |> (TYPE (Sym (D:R:Interpret[0])))_N) :: TYPE
                                                                (Interpret 'Red))
  Interpret 'Red
  Call stack:
      CallStack (from HasCallStack):
        callStackDoc, called at compiler/utils/Outputable.hs:1179:37 in ghc:Outputable
        pprPanic, called at compiler/simplStg/RepType.hs:525:5 in ghc:RepType

This leads me to wonder: which forms of data declarations are intended to actually support type families in their return kinds? The conclusion in #16821 (closed) seemed to be that normal data types do not support them. The existence of the UnliftedNewtypesDifficultUnification test case, on the other hand, seems to indicate that data family declarations (as well as data family instances) should support them. If this is true, how can we reconcile this with the problems observed above?

To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information
Assignee
Assign to
Time tracking