{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}

{-# OPTIONS_GHC -Wall #-}

-- | Bug(?) in Coercible constraint solving

module T13083 where

import Data.Kind
import GHC.Generics (Par1(..),(:*:)(..))
import GHC.Exts (coerce)

-- Representation as free vector space
type family V (a :: Type) :: Type -> Type

type instance V R = Par1
type instance V (a,b) = V a :*: V b

type instance V (Par1 a) = V a

data R = R

-- Linear map in row-major order
newtype L a b = L (V b (V a R))

-- Use coerce to drop newtype wrapper
bar :: L a b -> V b (V a R)
bar = coerce

{-
[W] L a b ~R V b (V a R)
-->
    V b (V a R)  ~R  V b (V a R)
-}

{--------------------------------------------------------------------
    Bug demo
--------------------------------------------------------------------}

-- A rejected type specialization of bar with a ~ (R,R), b ~ (Par1 R,R)
foo :: L (R,R) (Par1 R,R) -> V (Par1 R,R) (V (R,R) R)
-- foo :: L (a1,R) (Par1 b1,b2) -> V (Par1 b1,b2) (V (a1,R) R)
foo = coerce

{-
[W] L (a1,R) (Par1 b1, b2)   ~R   V (Par1 b1,b2) (V (a1,R) R)
-->
    V (Par1 b1, b2) (V (a1,R) R)  ~R    same

    -> (V (Par1 b1) :*: V b2) ((V a1 :*: V R) R)
    -> (:*:) (V b1) (V b2) (:*: (V a1) Par1 R)

-->
    L (a1,R) (Par1 b1, b2)   ~R   (:*:) (V b1) (V b2) (:*: (V a1) Par1 R)
-}

--     • Couldn't match representation of type ‘V Par1’
--                                with that of ‘Par1’
--         arising from a use of ‘coerce’

-- Note that Par1 has the wrong kind (Type -> Type) for V Par1

-- Same error:
--
-- foo :: (a ~ (R,R), b ~ (Par1 R,R)) => L a b -> V b (V a R)

-- The following similar signatures work:

-- foo :: L (R,R) (R,Par1 R) -> V (R,Par1 R) (V (R,R) R)
-- foo :: L (Par1 R,R) (R,R) -> V (R,R) (V (Par1 R,R) R)

-- Same error:

-- -- Linear map in column-major order
-- newtype L a b = L (V a (V b s))

-- foo :: L (R,R) (Par1 R,R) -> V (R,R) (V (Par1 R,R) R)
-- foo = coerce

