{-# OPTIONS_GHC -fobject-code #-}
{-# OPTIONS_HADDOCK hide, prune #-}
module Data.Type.List.InjectiveSnoc ( plugin ) where
import CoAxiom (CoAxBranch (..), CoAxiom (..), mapAccumBranches)
import Data.Maybe (fromMaybe)
import GhcPlugins
plugin :: Plugin
plugin = defaultPlugin
{ installCoreToDos =
const $ pure . (CoreDoPluginPass "InjectiveSnoc" injectiveSnocPass :)
}
injectiveSnocPass :: ModGuts -> CoreM ModGuts
injectiveSnocPass = pure . modSnocFam updateSnocFam
modSnocFam :: (TyCon -> TyCon) -> ModGuts -> ModGuts
modSnocFam f guts = guts {mg_tcs = map g (mg_tcs guts)}
where
g tc
| nameOccName (tyConName tc) == mkTcOcc "Snoc" = f tc
| otherwise = tc
updateSnocFam :: TyCon -> TyCon
updateSnocFam tc = fromMaybe tc $ do
axiom <- isClosedSynFamilyTyConWithAxiom_maybe tc
let newAxiom = axiom
{ co_ax_tc = newTc
, co_ax_branches = mapAccumBranches f (co_ax_branches axiom)
}
f _ b = b { cab_rhs = repTc (cab_rhs b) }
repTc t = case splitTyConApp_maybe t of
Just (c, ts)
| nameOccName (tyConName c) == mkTcOcc "Snoc"
-> mkTyConApp newTc $ map repTc ts
| otherwise
-> mkTyConApp c $ map repTc ts
Nothing
-> t
newTc = mkFamilyTyCon
(tyConName tc)
(tyConBinders tc)
(tyConResKind tc)
(famTcResVar tc)
(ClosedSynFamilyTyCon (Just newAxiom))
(tyConAssoc_maybe tc)
(Injective [True, True, True])
return newTc