Skip to content

Commit 9584d1a

Browse files
authored
Support type synonyms (#21)
* Transform type synonyms * Add example
1 parent 531ead2 commit 9584d1a

File tree

4 files changed

+66
-28
lines changed

4 files changed

+66
-28
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import TypeSynonymBase
2+
3+
data NoExt
4+
5+
extendExp "Exp" [] [t|NoExt|] defaultExtExp
6+
extendArg "Arg" [] [t|NoExt|] defaultExtArg
7+
type Args = Args' NoExt
8+
9+
main :: IO ()
10+
main = pure ()
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
module TypeSynonymBase where
2+
import Extensible
3+
4+
extensible [d|
5+
data Exp = App Exp Args | Var String
6+
data Arg = Arg String Exp
7+
type Args = [Arg]
8+
|]

extensible-data.cabal

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,12 @@ executable reused-name
112112
main-is: ReusedName.hs
113113
other-modules: ReusedNameBase
114114

115+
executable type-synonym
116+
import: deps, example
117+
hs-source-dirs: examples/type-synonym
118+
main-is: TypeSynonym.hs
119+
other-modules: TypeSynonymBase
120+
115121
executable lam
116122
import: deps, example
117123
hs-source-dirs: examples/lam

src/Extensible.hs

Lines changed: 42 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ import GHC.Generics (Generic)
283283
import Control.Monad
284284
import Data.Functor.Identity
285285
import Data.Void
286-
import Data.Kind as K
286+
import qualified Data.Kind as K
287287

288288
--
289289
deriving instance Lift Name
@@ -425,13 +425,21 @@ data SimpleCon = SimpleCon {
425425
data SimpleFields = NormalFields [BangType] | RecFields [VarBangType]
426426
deriving (Eq, Show, Data)
427427

428-
-- | A \"simple\" datatype (no context, no kind signature, no deriving)
429-
data SimpleData = SimpleData {
430-
sdName :: Name,
431-
sdVars :: [TyVarBndr],
432-
sdCons :: [SimpleCon],
433-
sdDerivs :: [SimpleDeriv]
434-
} deriving (Eq, Show, Data)
428+
-- | A \"simple\" datatype (no context, no kind signature, no deriving) or type
429+
-- synonym
430+
data SimpleDec =
431+
SimpleData {
432+
sdName :: Name,
433+
sdVars :: [TyVarBndr],
434+
sdCons :: [SimpleCon],
435+
sdDerivs :: [SimpleDeriv]
436+
}
437+
| SimpleType {
438+
sdName :: Name,
439+
sdVars :: [TyVarBndr],
440+
sdSynRhs :: Type
441+
}
442+
deriving (Eq, Show, Data)
435443

436444
-- 'SBlank' and 'SStock' have the same effect but the first will trigger
437445
-- @-Wmissing-deriving-strategies@ if it is enabled and the second requires
@@ -445,31 +453,32 @@ data SimpleDeriv =
445453
dsContext :: Cxt
446454
} deriving (Eq, Show, Data)
447455

448-
-- | Extract a 'SimpleData' from a 'Dec', if it is a datatype with the given
456+
-- | Extract a 'SimpleDec' from a 'Dec', if it is a datatype with the given
449457
-- restrictions.
450-
simpleData :: WarningType -> Dec -> Q SimpleData
451-
simpleData _w (DataD ctx name tvs kind cons derivs)
458+
simpleDec :: WarningType -> Dec -> Q SimpleDec
459+
simpleDec _w (DataD ctx name tvs kind cons derivs)
452460
| not $ null ctx = fail "data contexts unsupported"
453461
| Just _ <- kind = fail "kind signatures unsupported"
454462
| otherwise =
455463
SimpleData name tvs
456464
<$> traverse simpleCon cons
457465
<*> traverse simpleDeriv derivs
458-
simpleData Error (NewtypeD _ name _ _ _ _) =
466+
simpleDec Error (NewtypeD _ name _ _ _ _) =
459467
fail $
460468
"newtype " ++ nameBase name ++ " found\n" ++
461469
"please replace it with a datatype"
462-
simpleData Warn n@(NewtypeD _ name _ _ _ _) = do
470+
simpleDec Warn n@(NewtypeD _ name _ _ _ _) = do
463471
reportWarning $
464472
"replacing newtype " ++ nameBase name ++ " with data\n" ++
465473
"(due to adding another field and a second constructor)\n" ++
466474
"you may want to replace the newtype with a (strict) datatype"
467-
simpleData Ignore n
468-
simpleData Ignore (NewtypeD ctx name tvs kind con derivs) =
469-
simpleData Ignore $ DataD ctx name tvs kind [makeStrict con] derivs
475+
simpleDec Ignore n
476+
simpleDec Ignore (NewtypeD ctx name tvs kind con derivs) =
477+
simpleDec Ignore $ DataD ctx name tvs kind [makeStrict con] derivs
470478
where
471479
makeStrict = everywhere $ mkT $ const $ Bang NoSourceUnpackedness SourceStrict
472-
simpleData _w d =
480+
simpleDec _w (TySynD n tvs rhs) = pure $ SimpleType n tvs rhs
481+
simpleDec _w d =
473482
fail $
474483
"only datatype declarations are supported inside extensible; found\n" ++
475484
pprint d
@@ -499,7 +508,7 @@ extensible = extensibleWith defaultConfig
499508
-- function spits out.
500509
extensibleWith :: Config -> DecsQ -> DecsQ
501510
extensibleWith conf ds = do
502-
ds' <- traverse (simpleData (newtypeWarn conf)) =<< ds
511+
ds' <- traverse (simpleDec (newtypeWarn conf)) =<< ds
503512
home <- loc_module <$> location
504513
makeExtensible conf home ds'
505514

@@ -522,18 +531,18 @@ extIsRecord = all isRecordCon
522531

523532
makeExtensible :: Config
524533
-> String -- ^ module where @extensible{With}@ was called
525-
-> [SimpleData] -> DecsQ
526-
makeExtensible conf home datas =
534+
-> [SimpleDec] -> DecsQ
535+
makeExtensible conf home decs =
527536
let nameMap = [(name, applyAffix (datatypeName conf) name)
528-
| SimpleData {sdName = name} <- datas]
529-
in concat <$> mapM (makeExtensible1 conf home nameMap) datas
537+
| d <- decs, let name = sdName d]
538+
in concat <$> mapM (makeExtensible1 conf home nameMap) decs
530539

531540
makeExtensible1 :: Config
532541
-> String -- ^ module where @extensible{With}@ was called
533542
-> [(Name, Name)] -- ^ mapping @(old, new)@ for datatype names
534-
-> SimpleData -> DecsQ
543+
-> SimpleDec -> DecsQ
535544
makeExtensible1 conf home nameMap (SimpleData name tvs cs derivs) = do
536-
let name' = applyAffix (datatypeName conf) name
545+
let Just name' = lookup name nameMap
537546
ext <- newName "ext"
538547
let tvs' = PlainTV ext : tvs
539548
cs' <- traverse (extendCon conf nameMap ext tvs) cs
@@ -546,9 +555,13 @@ makeExtensible1 conf home nameMap (SimpleData name tvs cs derivs) = do
546555
(rname, fcnames, fname, rec) <- extRecord conf name cs
547556
(_dname, defRec) <- extRecDefault conf rname fcnames fname
548557
(_ename, extFun) <- makeExtender conf home name rname tvs cs
549-
return $
558+
pure $
550559
DataD [] name' tvs' Nothing (cs' ++ [cx]) [] :
551560
efs ++ [efx, bnd] ++ insts ++ [rec] ++ defRec ++ extFun
561+
makeExtensible1 _conf _home nameMap (SimpleType name tvs rhs) = do
562+
let Just name' = lookup name nameMap
563+
ext <- newName "ext"
564+
pure [TySynD name' (PlainTV ext : tvs) $ extendRecursions nameMap ext rhs]
552565

553566
nonstrict :: BangQ
554567
nonstrict = bang noSourceUnpackedness noSourceStrictness
@@ -579,9 +592,10 @@ extendCon conf nameMap ext tvs (SimpleCon name fields) = do
579592
pure $ RecC name' $ fs ++ [(extLabel, strict, extField)]
580593

581594
-- | Replaces recursive occurences of the datatype with the new one.
582-
extendRecursions :: [(Name, Name)] -- ^ original & new datatype names
595+
extendRecursions :: Data a
596+
=> [(Name, Name)] -- ^ original & new datatype names
583597
-> Name -- ^ new type variable name
584-
-> SimpleFields -> SimpleFields
598+
-> a -> a
585599
extendRecursions nameMap ext = everywhere $ mkT go where
586600
go (ConT k) | Just new <- lookup k nameMap = ConT new `AppT` VarT ext
587601
go t = t
@@ -616,7 +630,7 @@ constraintBundle :: Config
616630
-> [TyVarBndr] -> [SimpleCon] -> DecQ
617631
constraintBundle conf name ext tvs cs = do
618632
c <- newName "c"
619-
ckind <- [t|K.Type -> Constraint|]
633+
ckind <- [t|K.Type -> K.Constraint|]
620634
let cnames = map scName cs
621635
bname = applyAffix (bundleName conf) name
622636
tvs' = kindedTV c ckind : plainTV ext : tvs

0 commit comments

Comments
 (0)