Skip to content

Backpack can end up confused when a non-nullary type synonym implements abstract data

GHC seems to get confused with the following .bkp backpack file modified from test case T13955 in which an argument is added to the Rep declaration:

{-# LANGUAGE MagicHash #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE DataKinds #-}

unit number-unknown where
  signature NumberUnknown where
    import GHC.Types
    data Rep a :: RuntimeRep
    data Number a :: TYPE (Rep a)
    plus :: Number a -> Number a -> Number a
    multiply :: Number a -> Number a -> Number a
  module NumberStuff where
    import NumberUnknown
    funcA :: Number a -> Number a -> Number a
    funcA x y = plus x (multiply x y)

unit number-unboxed-int where
  module NumberUnknown where
    import GHC.Types
    import GHC.Prim
    type Rep a = IntRep
    type Number a = Int#
    plus :: Int# -> Int# -> Int#
    plus = (+#)
    multiply :: Int# -> Int# -> Int#
    multiply = (*#)

unit main where
  dependency number-unknown[NumberUnknown=number-unboxed-int:NumberUnknown]
  module Main where
    import NumberStuff
    import GHC.Types
    main = print (I# (funcA 2# 3#))

Compiled with ghc T20133.bkp --backpack, we get the error:

T13955b.bkp:15:14: error:
    * Expected kind `k0 -> *',
        but `Number' has kind `TYPE 'GHC.Types.IntRep'
    * In the type signature: funcA :: Number a -> Number a -> Number a
   |
15 |     funcA :: Number a -> Number a -> Number a
   |              ^^^^^^^^

T13955b.bkp:15:26: error:
    * Expected kind `k0 -> *',
        but `Number' has kind `TYPE 'GHC.Types.IntRep'
    * In the type signature: funcA :: Number a -> Number a -> Number a
   |
15 |     funcA :: Number a -> Number a -> Number a
   |                          ^^^^^^^^

T13955b.bkp:15:38: error:
    * Expected kind `k0 -> *',
        but `Number' has kind `TYPE 'GHC.Types.IntRep'
    * In the type signature: funcA :: Number a -> Number a -> Number a
   |
15 |     funcA :: Number a -> Number a -> Number a
   |                                      ^^^^^^^^

It looks like GHC gets confused when typechecking main (indeed, commenting it out prevents the error); so the line numbers should be understood as referring to the instantiation of the NumberUnknown signature.
This is what -ddump-tc-trace looks like starting from there:

[3 of 3] Processing main
  Instantiating main
  [1 of 1] Including number-unknown[NumberUnknown=number-unboxed-int:NumberUnknown]
    Instantiating number-unknown[NumberUnknown=number-unboxed-int:NumberUnknown]
    [1 of 2] Compiling NumberUnknown[sig] ( number-unknown\NumberUnknown.hsig, nothing ) [Source file changed]
checkHsigIface
  [ryc :-> Identifier `multiply', ryd :-> Identifier `plus',
   rye :-> Type constructor `Number', ryf :-> Type constructor `Rep',
   ryg :-> Identifier `number-unboxed-int:NumberUnknown.$trModule',
   ryU :-> Identifier `number-unboxed-int:NumberUnknown.$tcNumber',
   ryV :-> Identifier `number-unboxed-int:NumberUnknown.$tcRep']
  []
  [multiply, plus, Number{Number}, Rep{Rep}]
    [2 of 2] Compiling NumberStuff      ( number-unknown\NumberStuff.hs, nothing ) [Source file changed]
Adding diagnostic:
  testsuite\tests\backpack\should_run\T13955b.bkp:13:3:
      Module `Prelude' implicitly imported
checkFamInstConsistency [Prelude, NumberUnknown]
Tc2 (src)
Tc3
tcExtendKindEnvList []
tcExtendKindEnvList []
tcDeriving []
rnd
Adding instances:
Tc3b
Tc3c
tcSemigroupWarnings
Tc4
Tc4a
Tc5
tcExtendKindEnvList []
tcHsSigType { Number a_ayY -> Number a_ayY -> Number a_ayY
pushLevelAndSolveEqualitiesX { Called from tc_lhs_sig_type
newAnonMetaTyVar t_az1[tau:1]
pushLevelAndCaptureConstraints { 2
newMetaKindVar k_az2[tau:2]
bindImplicitTKBndrsX
  [a_ayY]
  [a_ayY[sk:2]]
tc_extend_local_env
  [(a_ayY, Type variable `a_ayY' = a_ayY[sk:2] :: k_az2[tau:2])]
tcExtendBinderStack [a_ayY a_ayY[sk:2]]
newAnonMetaTyVar t_az3[tau:2]
newAnonMetaTyVar t_az4[tau:2]
lk1 Number
tcInferTyApps {
  Number
  [HsValArg a_ayY]
newMetaKindVar k_az5[tau:2]
newMetaKindVar k_az6[tau:2]
u_tys
  tclvl 2
  TYPE 'GHC.Types.IntRep ~ k_az5[tau:2] -> k_az6[tau:2]
  a type equality[True] TYPE 'GHC.Types.IntRep
                        ~
                        k_az5[tau:2] -> k_az6[tau:2]

We see here that GHC gets confused about the kind of Number (it thinks Number :: TYPE IntRep, somehow ignoring that Number takes an argument), and it all goes downhill from there.

Sorry for the ticket title, I didn't really know how to summarise the issue. I'm not very familiar with backpack, so I apologise if I made an elementary error somewhere.

Edited by sheaf
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information