{-# LANGUAGE CPP #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
#if __GLASGOW_HASKELL__ < 806
{-# OPTIONS_GHC -Wwarn=unused-pattern-binds #-}
#endif
module Clash.Class.AutoReg.Internal
( AutoReg (..)
, deriveAutoReg
, deriveAutoRegTuples
)
where
import Data.List (nub,zipWith4)
import Data.Maybe (fromMaybe,isJust)
import GHC.Stack (HasCallStack)
import GHC.TypeNats (KnownNat,Nat,type (+))
import Clash.Explicit.Signal
import Clash.Promoted.Nat
import Clash.Magic
import Clash.XException (NFDataX, deepErrorX)
import Clash.Sized.BitVector
import Clash.Sized.Fixed
import Clash.Sized.Index
import Clash.Sized.RTree
import Clash.Sized.Signed
import Clash.Sized.Unsigned
import Clash.Sized.Vector (Vec, lazyV, smap)
import Data.Int
import Data.Word
import Foreign.C.Types (CUShort)
import Numeric.Half (Half)
import Language.Haskell.TH.Datatype
import Language.Haskell.TH.Syntax
import Language.Haskell.TH.Lib
import Language.Haskell.TH.Ppr
import Control.Lens.Internal.TH (bndrName, conAppsT)
class NFDataX a => AutoReg a where
autoReg
:: (HasCallStack, KnownDomain dom)
=> Clock dom -> Reset dom -> Enable dom
-> a
-> Signal dom a
-> Signal dom a
autoReg = Clock dom
-> Reset dom -> Enable dom -> a -> Signal dom a -> Signal dom a
forall (dom :: Domain) a.
(KnownDomain dom, NFDataX a) =>
Clock dom
-> Reset dom -> Enable dom -> a -> Signal dom a -> Signal dom a
register
{-# INLINE autoReg #-}
instance AutoReg ()
instance AutoReg Bool
instance AutoReg Double
instance AutoReg Float
instance AutoReg CUShort
instance AutoReg Half
instance AutoReg Char
instance AutoReg Integer
instance AutoReg Int
instance AutoReg Int8
instance AutoReg Int16
instance AutoReg Int32
instance AutoReg Int64
instance AutoReg Word
instance AutoReg Word8
instance AutoReg Word16
instance AutoReg Word32
instance AutoReg Word64
instance AutoReg Bit
instance AutoReg (BitVector n)
instance AutoReg (Signed n)
instance AutoReg (Unsigned n)
instance AutoReg (Index n)
instance NFDataX (rep (int + frac)) => AutoReg (Fixed rep int frac)
instance AutoReg a => AutoReg (Maybe a) where
autoReg :: Clock dom
-> Reset dom
-> Enable dom
-> Maybe a
-> Signal dom (Maybe a)
-> Signal dom (Maybe a)
autoReg Clock dom
clk Reset dom
rst Enable dom
en Maybe a
initVal Signal dom (Maybe a)
input =
Bool -> a -> Maybe a
forall a. Bool -> a -> Maybe a
createMaybe (Bool -> a -> Maybe a)
-> Signal dom Bool -> Signal dom (a -> Maybe a)
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> Signal dom Bool
tagR Signal dom (a -> Maybe a) -> Signal dom a -> Signal dom (Maybe a)
forall (f :: Type -> Type) a b.
Applicative f =>
f (a -> b) -> f a -> f b
<*> Signal dom a
valR
where
tag :: Signal dom Bool
tag = Maybe a -> Bool
forall a. Maybe a -> Bool
isJust (Maybe a -> Bool) -> Signal dom (Maybe a) -> Signal dom Bool
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> Signal dom (Maybe a)
input
tagInit :: Bool
tagInit = Maybe a -> Bool
forall a. Maybe a -> Bool
isJust Maybe a
initVal
tagR :: Signal dom Bool
tagR = Clock dom
-> Reset dom
-> Enable dom
-> Bool
-> Signal dom Bool
-> Signal dom Bool
forall (dom :: Domain) a.
(KnownDomain dom, NFDataX a) =>
Clock dom
-> Reset dom -> Enable dom -> a -> Signal dom a -> Signal dom a
register Clock dom
clk Reset dom
rst Enable dom
en Bool
tagInit Signal dom Bool
tag
val :: Signal dom a
val = a -> Maybe a -> a
forall a. a -> Maybe a -> a
fromMaybe (String -> a
forall a. (NFDataX a, HasCallStack) => String -> a
deepErrorX String
"autoReg'.val") (Maybe a -> a) -> Signal dom (Maybe a) -> Signal dom a
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> Signal dom (Maybe a)
input
valInit :: a
valInit = a -> Maybe a -> a
forall a. a -> Maybe a -> a
fromMaybe (String -> a
forall a. (NFDataX a, HasCallStack) => String -> a
deepErrorX String
"autoReg'.valInit") Maybe a
initVal
valR :: Signal dom a
valR = Clock dom
-> Reset dom -> Enable dom -> a -> Signal dom a -> Signal dom a
forall a (dom :: Domain).
(AutoReg a, HasCallStack, KnownDomain dom) =>
Clock dom
-> Reset dom -> Enable dom -> a -> Signal dom a -> Signal dom a
autoReg Clock dom
clk Reset dom
rst (Enable dom -> Signal dom Bool -> Enable dom
forall (dom :: Domain). Enable dom -> Signal dom Bool -> Enable dom
enable Enable dom
en Signal dom Bool
tag) a
valInit Signal dom a
val
createMaybe :: Bool -> a -> Maybe a
createMaybe Bool
t a
v = case Bool
t of
Bool
True -> a -> Maybe a
forall a. a -> Maybe a
Just a
v
Bool
False -> Maybe a
forall a. Maybe a
Nothing
{-# INLINE autoReg #-}
instance (KnownNat n, AutoReg a) => AutoReg (Vec n a) where
autoReg
:: forall dom. (HasCallStack, KnownDomain dom)
=> Clock dom -> Reset dom -> Enable dom
-> Vec n a
-> Signal dom (Vec n a)
-> Signal dom (Vec n a)
autoReg :: Clock dom
-> Reset dom
-> Enable dom
-> Vec n a
-> Signal dom (Vec n a)
-> Signal dom (Vec n a)
autoReg Clock dom
clk Reset dom
rst Enable dom
en Vec n a
initVal Signal dom (Vec n a)
xs =
Unbundled dom (Vec n a) -> Signal dom (Vec n a)
forall a (dom :: Domain).
Bundle a =>
Unbundled dom a -> Signal dom a
bundle (Unbundled dom (Vec n a) -> Signal dom (Vec n a))
-> Unbundled dom (Vec n a) -> Signal dom (Vec n a)
forall a b. (a -> b) -> a -> b
$ (forall (l :: Nat). SNat l -> a -> Signal dom a -> Signal dom a)
-> Vec n a -> Vec n (Signal dom a -> Signal dom a)
forall (k :: Nat) a b.
KnownNat k =>
(forall (l :: Nat). SNat l -> a -> b) -> Vec k a -> Vec k b
smap forall (l :: Nat). SNat l -> a -> Signal dom a -> Signal dom a
go (Vec n a -> Vec n a
forall (n :: Nat) a. KnownNat n => Vec n a -> Vec n a
lazyV Vec n a
initVal) Vec n (Signal dom a -> Signal dom a)
-> Vec n (Signal dom a) -> Vec n (Signal dom a)
forall (f :: Type -> Type) a b.
Applicative f =>
f (a -> b) -> f a -> f b
<*> Signal dom (Vec n a) -> Unbundled dom (Vec n a)
forall a (dom :: Domain).
Bundle a =>
Signal dom a -> Unbundled dom a
unbundle Signal dom (Vec n a)
xs
where
go :: forall (i :: Nat). SNat i -> a -> Signal dom a -> Signal dom a
go :: SNat i -> a -> Signal dom a -> Signal dom a
go SNat i
SNat = forall a. a -> a
forall (name :: Nat) a. a -> a
suffixNameFromNatP @i ((Signal dom a -> Signal dom a) -> Signal dom a -> Signal dom a)
-> (a -> Signal dom a -> Signal dom a)
-> a
-> Signal dom a
-> Signal dom a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Clock dom
-> Reset dom -> Enable dom -> a -> Signal dom a -> Signal dom a
forall a (dom :: Domain).
(AutoReg a, HasCallStack, KnownDomain dom) =>
Clock dom
-> Reset dom -> Enable dom -> a -> Signal dom a -> Signal dom a
autoReg Clock dom
clk Reset dom
rst Enable dom
en
{-# INLINE autoReg #-}
instance (KnownNat d, AutoReg a) => AutoReg (RTree d a) where
autoReg :: Clock dom
-> Reset dom
-> Enable dom
-> RTree d a
-> Signal dom (RTree d a)
-> Signal dom (RTree d a)
autoReg Clock dom
clk Reset dom
rst Enable dom
en RTree d a
initVal Signal dom (RTree d a)
xs =
Unbundled dom (RTree d a) -> Signal dom (RTree d a)
forall a (dom :: Domain).
Bundle a =>
Unbundled dom a -> Signal dom a
bundle (Unbundled dom (RTree d a) -> Signal dom (RTree d a))
-> Unbundled dom (RTree d a) -> Signal dom (RTree d a)
forall a b. (a -> b) -> a -> b
$ (Clock dom
-> Reset dom -> Enable dom -> a -> Signal dom a -> Signal dom a
forall a (dom :: Domain).
(AutoReg a, HasCallStack, KnownDomain dom) =>
Clock dom
-> Reset dom -> Enable dom -> a -> Signal dom a -> Signal dom a
autoReg Clock dom
clk Reset dom
rst Enable dom
en) (a -> Signal dom a -> Signal dom a)
-> RTree d a -> RTree d (Signal dom a -> Signal dom a)
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> RTree d a -> RTree d a
forall (d :: Nat) a. KnownNat d => RTree d a -> RTree d a
lazyT RTree d a
initVal RTree d (Signal dom a -> Signal dom a)
-> RTree d (Signal dom a) -> RTree d (Signal dom a)
forall (f :: Type -> Type) a b.
Applicative f =>
f (a -> b) -> f a -> f b
<*> Signal dom (RTree d a) -> Unbundled dom (RTree d a)
forall a (dom :: Domain).
Bundle a =>
Signal dom a -> Unbundled dom a
unbundle Signal dom (RTree d a)
xs
{-# INLINE autoReg #-}
unfoldType :: Type -> (Type, [Type])
unfoldType :: Type -> (Type, [Type])
unfoldType = [Type] -> Type -> (Type, [Type])
go []
where
go :: [Type] -> Type -> (Type, [Type])
go :: [Type] -> Type -> (Type, [Type])
go [Type]
acc (ForallT [TyVarBndr]
_ [Type]
_ Type
ty) = [Type] -> Type -> (Type, [Type])
go [Type]
acc Type
ty
go [Type]
acc (AppT Type
ty1 Type
ty2) = [Type] -> Type -> (Type, [Type])
go (Type
ty2Type -> [Type] -> [Type]
forall a. a -> [a] -> [a]
:[Type]
acc) Type
ty1
go [Type]
acc (SigT Type
ty Type
_) = [Type] -> Type -> (Type, [Type])
go [Type]
acc Type
ty
#if MIN_VERSION_template_haskell(2,11,0)
go [Type]
acc (ParensT Type
ty) = [Type] -> Type -> (Type, [Type])
go [Type]
acc Type
ty
#endif
#if MIN_VERSION_template_haskell(2,15,0)
go [Type]
acc (AppKindT Type
ty Type
_) = [Type] -> Type -> (Type, [Type])
go [Type]
acc Type
ty
#endif
go [Type]
acc Type
ty = (Type
ty, [Type]
acc)
deriveAutoReg :: Name -> DecsQ
deriveAutoReg :: Name -> DecsQ
deriveAutoReg Name
tyNm = do
DatatypeInfo
tyInfo <- Name -> Q DatatypeInfo
reifyDatatype Name
tyNm
case DatatypeInfo -> [ConstructorInfo]
datatypeCons DatatypeInfo
tyInfo of
[] -> String -> DecsQ
forall (m :: Type -> Type) a. MonadFail m => String -> m a
fail String
"Can't deriveAutoReg for empty types"
[ConstructorInfo
conInfo] -> DatatypeInfo -> ConstructorInfo -> DecsQ
deriveAutoRegProduct DatatypeInfo
tyInfo ConstructorInfo
conInfo
[ConstructorInfo]
_ -> String -> DecsQ
forall (m :: Type -> Type) a. MonadFail m => String -> m a
fail String
"Can't deriveAutoReg for sum types"
deriveAutoRegProduct :: DatatypeInfo -> ConstructorInfo -> DecsQ
deriveAutoRegProduct :: DatatypeInfo -> ConstructorInfo -> DecsQ
deriveAutoRegProduct DatatypeInfo
tyInfo ConstructorInfo
conInfo = Name -> [(Maybe Name, Type)] -> DecsQ
go (ConstructorInfo -> Name
constructorName ConstructorInfo
conInfo) [(Maybe Name, Type)]
fieldInfos
where
tyNm :: Name
tyNm = DatatypeInfo -> Name
datatypeName DatatypeInfo
tyInfo
tyVarBndrs :: [TyVarBndr]
tyVarBndrs = DatatypeInfo -> [TyVarBndr]
datatypeVars DatatypeInfo
tyInfo
#if MIN_VERSION_th_abstraction(0,3,0)
toTyVar :: TyVarBndr -> Type
toTyVar = Name -> Type
VarT (Name -> Type) -> (TyVarBndr -> Name) -> TyVarBndr -> Type
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TyVarBndr -> Name
bndrName
#else
toTyVar t = case t of
VarT _ -> t
SigT t' _ -> toTyVar t'
_ -> error "deriveAutoRegProduct.toTv"
#endif
tyVars :: [Type]
tyVars = (TyVarBndr -> Type) -> [TyVarBndr] -> [Type]
forall a b. (a -> b) -> [a] -> [b]
map TyVarBndr -> Type
toTyVar [TyVarBndr]
tyVarBndrs
ty :: Type
ty = Name -> [Type] -> Type
conAppsT Name
tyNm [Type]
tyVars
fieldInfos :: [(Maybe Name, Type)]
fieldInfos =
[Maybe Name] -> [Type] -> [(Maybe Name, Type)]
forall a b. [a] -> [b] -> [(a, b)]
zip [Maybe Name]
fieldNames (ConstructorInfo -> [Type]
constructorFields ConstructorInfo
conInfo)
where
fieldNames :: [Maybe Name]
fieldNames =
case ConstructorInfo -> ConstructorVariant
constructorVariant ConstructorInfo
conInfo of
RecordConstructor [Name]
nms -> (Name -> Maybe Name) -> [Name] -> [Maybe Name]
forall a b. (a -> b) -> [a] -> [b]
map Name -> Maybe Name
forall a. a -> Maybe a
Just [Name]
nms
ConstructorVariant
_ -> Maybe Name -> [Maybe Name]
forall a. a -> [a]
repeat Maybe Name
forall a. Maybe a
Nothing
go :: Name -> [(Maybe Name,Type)] -> Q [Dec]
go :: Name -> [(Maybe Name, Type)] -> DecsQ
go Name
dcNm [(Maybe Name, Type)]
fields = do
[Name]
args <- (String -> Q Name) -> [String] -> Q [Name]
forall (t :: Type -> Type) (m :: Type -> Type) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM String -> Q Name
newName [String
"clk", String
"rst", String
"en", String
"initVal", String
"input"]
let
[ExpQ
clkE, ExpQ
rstE, ExpQ
enE, ExpQ
initValE, ExpQ
inputE] = (Name -> ExpQ) -> [Name] -> [ExpQ]
forall a b. (a -> b) -> [a] -> [b]
map Name -> ExpQ
varE [Name]
args
argsP :: [PatQ]
argsP = (Name -> PatQ) -> [Name] -> [PatQ]
forall a b. (a -> b) -> [a] -> [b]
map Name -> PatQ
varP [Name]
args
fieldNames :: [Maybe Name]
fieldNames = ((Maybe Name, Type) -> Maybe Name)
-> [(Maybe Name, Type)] -> [Maybe Name]
forall a b. (a -> b) -> [a] -> [b]
map (Maybe Name, Type) -> Maybe Name
forall a b. (a, b) -> a
fst [(Maybe Name, Type)]
fields
field :: Name -> Int -> DecQ
field :: Name -> Int -> DecQ
field Name
nm Int
nr =
PatQ -> BodyQ -> [DecQ] -> DecQ
valD (Name -> PatQ
varP Name
nm) (ExpQ -> BodyQ
normalB [| $fieldSel <$> $inputE |]) []
where
fieldSel :: ExpQ
fieldSel = do
Name
xNm <- String -> Q Name
newName String
"x"
let fieldP :: [PatQ]
fieldP = [ if Int
nr Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
n then Name -> PatQ
varP Name
xNm else PatQ
wildP
| (Int
n,(Maybe Name, Type)
_) <- [Int] -> [(Maybe Name, Type)] -> [(Int, (Maybe Name, Type))]
forall a b. [a] -> [b] -> [(a, b)]
zip [Int
0..] [(Maybe Name, Type)]
fields]
[PatQ] -> ExpQ -> ExpQ
lamE [Name -> [PatQ] -> PatQ
conP Name
dcNm [PatQ]
fieldP] (Name -> ExpQ
varE Name
xNm)
[Name]
parts <- String -> [(Maybe Name, Type)] -> Q [Name]
forall a. String -> [a] -> Q [Name]
generateNames String
"field" [(Maybe Name, Type)]
fields
[Dec]
fieldDecls <- [DecQ] -> DecsQ
forall (t :: Type -> Type) (m :: Type -> Type) a.
(Traversable t, Monad m) =>
t (m a) -> m (t a)
sequence ([DecQ] -> DecsQ) -> [DecQ] -> DecsQ
forall a b. (a -> b) -> a -> b
$ (Name -> Int -> DecQ) -> [Name] -> [Int] -> [DecQ]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith Name -> Int -> DecQ
field [Name]
parts [Int
0..]
[Name]
sigs <- String -> [(Maybe Name, Type)] -> Q [Name]
forall a. String -> [a] -> Q [Name]
generateNames String
"sig" [(Maybe Name, Type)]
fields
[Name]
initVals <- String -> [(Maybe Name, Type)] -> Q [Name]
forall a. String -> [a] -> Q [Name]
generateNames String
"initVal" [(Maybe Name, Type)]
fields
let initPat :: PatQ
initPat = Name -> [PatQ] -> PatQ
conP Name
dcNm ((Name -> PatQ) -> [Name] -> [PatQ]
forall a b. (a -> b) -> [a] -> [b]
map Name -> PatQ
varP [Name]
initVals)
Dec
initDecl <- PatQ -> BodyQ -> [DecQ] -> DecQ
valD PatQ
initPat (ExpQ -> BodyQ
normalB ExpQ
initValE) []
let
genAutoRegDecl :: PatQ -> ExpQ -> ExpQ -> Maybe Name -> DecsQ
genAutoRegDecl :: PatQ -> ExpQ -> ExpQ -> Maybe Name -> DecsQ
genAutoRegDecl PatQ
s ExpQ
v ExpQ
i Maybe Name
nameM =
[d| $s = $nameMe autoReg $clkE $rstE $enE $i $v |]
where
nameMe :: ExpQ
nameMe = case Maybe Name
nameM of
Maybe Name
Nothing -> [| id |]
Just Name
nm -> let nmSym :: TypeQ
nmSym = TyLitQ -> TypeQ
litT (TyLitQ -> TypeQ) -> TyLitQ -> TypeQ
forall a b. (a -> b) -> a -> b
$ String -> TyLitQ
strTyLit (Name -> String
nameBase Name
nm)
in [| suffixNameP @($nmSym) |]
[Dec]
partDecls <- [[Dec]] -> [Dec]
forall (t :: Type -> Type) a. Foldable t => t [a] -> [a]
concat ([[Dec]] -> [Dec]) -> Q [[Dec]] -> DecsQ
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> ([DecsQ] -> Q [[Dec]]
forall (t :: Type -> Type) (m :: Type -> Type) a.
(Traversable t, Monad m) =>
t (m a) -> m (t a)
sequence ([DecsQ] -> Q [[Dec]]) -> [DecsQ] -> Q [[Dec]]
forall a b. (a -> b) -> a -> b
$ (PatQ -> ExpQ -> ExpQ -> Maybe Name -> DecsQ)
-> [PatQ] -> [ExpQ] -> [ExpQ] -> [Maybe Name] -> [DecsQ]
forall a b c d e.
(a -> b -> c -> d -> e) -> [a] -> [b] -> [c] -> [d] -> [e]
zipWith4 PatQ -> ExpQ -> ExpQ -> Maybe Name -> DecsQ
genAutoRegDecl
(Name -> PatQ
varP (Name -> PatQ) -> [Name] -> [PatQ]
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> [Name]
sigs)
(Name -> ExpQ
varE (Name -> ExpQ) -> [Name] -> [ExpQ]
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> [Name]
parts)
(Name -> ExpQ
varE (Name -> ExpQ) -> [Name] -> [ExpQ]
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> [Name]
initVals)
([Maybe Name]
fieldNames)
)
let
decls :: [DecQ]
decls :: [DecQ]
decls = (Dec -> DecQ) -> [Dec] -> [DecQ]
forall a b. (a -> b) -> [a] -> [b]
map Dec -> DecQ
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure (Dec
initDecl Dec -> [Dec] -> [Dec]
forall a. a -> [a] -> [a]
: [Dec]
fieldDecls [Dec] -> [Dec] -> [Dec]
forall a. [a] -> [a] -> [a]
++ [Dec]
partDecls)
tyConE :: ExpQ
tyConE = Name -> ExpQ
conE Name
dcNm
body :: ExpQ
body =
case (Name -> ExpQ) -> [Name] -> [ExpQ]
forall a b. (a -> b) -> [a] -> [b]
map Name -> ExpQ
varE [Name]
sigs of
(ExpQ
sig0:[ExpQ]
rest) -> (ExpQ -> ExpQ -> ExpQ) -> ExpQ -> [ExpQ] -> ExpQ
forall (t :: Type -> Type) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl
(\ExpQ
acc ExpQ
sigN -> [| $acc <*> $sigN |])
[| $tyConE <$> $sig0 |]
[ExpQ]
rest
[] -> [| $tyConE |]
Dec
autoRegDec <- Name -> [ClauseQ] -> DecQ
funD 'autoReg [[PatQ] -> BodyQ -> [DecQ] -> ClauseQ
clause [PatQ]
argsP (ExpQ -> BodyQ
normalB ExpQ
body) [DecQ]
decls]
[Type]
ctx <- ConstructorInfo -> Q [Type]
calculateRequiredContext ConstructorInfo
conInfo
[Dec] -> DecsQ
forall (m :: Type -> Type) a. Monad m => a -> m a
return [Maybe Overlap -> [Type] -> Type -> [Dec] -> Dec
InstanceD Maybe Overlap
forall a. Maybe a
Nothing [Type]
ctx (Type -> Type -> Type
AppT (Name -> Type
ConT ''AutoReg) Type
ty)
[ Dec
autoRegDec
, Pragma -> Dec
PragmaD (Name -> Inline -> RuleMatch -> Phases -> Pragma
InlineP 'autoReg Inline
Inline RuleMatch
FunLike Phases
AllPhases) ]]
calculateRequiredContext :: ConstructorInfo -> Q Cxt
calculateRequiredContext :: ConstructorInfo -> Q [Type]
calculateRequiredContext ConstructorInfo
conInfo = do
let fieldTys :: [Type]
fieldTys = ConstructorInfo -> [Type]
constructorFields ConstructorInfo
conInfo
[[Type]]
wantedInstances <- (Type -> Q [Type]) -> [Type] -> Q [[Type]]
forall (t :: Type -> Type) (m :: Type -> Type) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (\Type
ty -> Name -> [Type] -> Q [Type]
constraintsWantedFor ''AutoReg [Type
ty]) ([Type] -> [Type]
forall a. Eq a => [a] -> [a]
nub [Type]
fieldTys)
[Type] -> Q [Type]
forall (m :: Type -> Type) a. Monad m => a -> m a
return ([Type] -> Q [Type]) -> [Type] -> Q [Type]
forall a b. (a -> b) -> a -> b
$ [Type] -> [Type]
forall a. Eq a => [a] -> [a]
nub ([[Type]] -> [Type]
forall (t :: Type -> Type) a. Foldable t => t [a] -> [a]
concat [[Type]]
wantedInstances)
constraintsWantedFor :: Name -> [Type] -> Q Cxt
constraintsWantedFor :: Name -> [Type] -> Q [Type]
constraintsWantedFor Name
clsNm [Type]
tys
| Name -> String
forall a. Show a => a -> String
show Name
clsNm String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
"GHC.TypeNats.KnownNat" = do
[Type] -> Q [Type]
forall (m :: Type -> Type) a. Monad m => a -> m a
return [Name -> [Type] -> Type
conAppsT Name
clsNm [Type]
tys]
constraintsWantedFor Name
clsNm [Type
ty] = case Type
ty of
VarT Name
_ -> [Type] -> Q [Type]
forall (m :: Type -> Type) a. Monad m => a -> m a
return [Type -> Type -> Type
AppT (Name -> Type
ConT Name
clsNm) Type
ty]
ConT Name
_ -> [Type] -> Q [Type]
forall (m :: Type -> Type) a. Monad m => a -> m a
return []
Type
_ -> do
[Dec]
insts <- Name -> [Type] -> DecsQ
reifyInstances Name
clsNm [Type
ty]
case [Dec]
insts of
[InstanceD Maybe Overlap
_ [Type]
cxtInst (AppT Type
autoRegCls Type
instTy) [Dec]
_]
| Type
autoRegCls Type -> Type -> Bool
forall a. Eq a => a -> a -> Bool
== Name -> Type
ConT Name
clsNm -> do
let substs :: [(Name, Type)]
substs = Type -> Type -> [(Name, Type)]
findTyVarSubsts Type
instTy Type
ty
cxt2 :: [Type]
cxt2 = (Type -> Type) -> [Type] -> [Type]
forall a b. (a -> b) -> [a] -> [b]
map ([(Name, Type)] -> Type -> Type
applyTyVarSubsts [(Name, Type)]
substs) [Type]
cxtInst
okCxt :: [Type]
okCxt = (Type -> Bool) -> [Type] -> [Type]
forall a. (a -> Bool) -> [a] -> [a]
filter Type -> Bool
isOk [Type]
cxt2
recurseCxt :: [Type]
recurseCxt = (Type -> Bool) -> [Type] -> [Type]
forall a. (a -> Bool) -> [a] -> [a]
filter Type -> Bool
needRecurse [Type]
cxt2
[[Type]]
recursed <- (Type -> Q [Type]) -> [Type] -> Q [[Type]]
forall (t :: Type -> Type) (m :: Type -> Type) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM Type -> Q [Type]
recurse [Type]
recurseCxt
[Type] -> Q [Type]
forall (m :: Type -> Type) a. Monad m => a -> m a
return ([Type]
okCxt [Type] -> [Type] -> [Type]
forall a. [a] -> [a] -> [a]
++ [[Type]] -> [Type]
forall (t :: Type -> Type) a. Foldable t => t [a] -> [a]
concat [[Type]]
recursed)
[] -> String -> Q [Type]
forall (m :: Type -> Type) a. MonadFail m => String -> m a
fail (String -> Q [Type]) -> String -> Q [Type]
forall a b. (a -> b) -> a -> b
$ String
"Missing instance " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Name -> String
forall a. Show a => a -> String
show Name
clsNm String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" (" String -> String -> String
forall a. [a] -> [a] -> [a]
++ Type -> String
forall a. Ppr a => a -> String
pprint Type
ty String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
")"
(Dec
_:Dec
_:[Dec]
_) -> String -> Q [Type]
forall (m :: Type -> Type) a. MonadFail m => String -> m a
fail (String -> Q [Type]) -> String -> Q [Type]
forall a b. (a -> b) -> a -> b
$ String
"There are multiple " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Name -> String
forall a. Show a => a -> String
show Name
clsNm String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" instances for "
String -> String -> String
forall a. [a] -> [a] -> [a]
++ Type -> String
forall a. Ppr a => a -> String
pprint Type
ty String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
":\n" String -> String -> String
forall a. [a] -> [a] -> [a]
++ [Dec] -> String
forall a. Ppr a => a -> String
pprint [Dec]
insts
[Dec]
_ -> String -> Q [Type]
forall (m :: Type -> Type) a. MonadFail m => String -> m a
fail (String -> Q [Type]) -> String -> Q [Type]
forall a b. (a -> b) -> a -> b
$ String
"Got unexpected instance: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ [Dec] -> String
forall a. Ppr a => a -> String
pprint [Dec]
insts
where
isOk :: Type -> Bool
isOk :: Type -> Bool
isOk (Type -> (Type, [Type])
unfoldType -> (Type
_cls,[Type]
tys)) =
case [Type]
tys of
[VarT Name
_] -> Bool
True
[Type
_] -> Bool
False
[Type]
_ -> Bool
True
needRecurse :: Type -> Bool
needRecurse :: Type -> Bool
needRecurse (Type -> (Type, [Type])
unfoldType -> (Type
cls,[Type]
tys)) =
case [Type]
tys of
[VarT Name
_] -> Bool
False
[ConT Name
_] -> Bool
False
[AppT Type
_ Type
_] -> Bool
True
[Type
_] -> String -> Bool
forall a. HasCallStack => String -> a
error ( String
"Error while deriveAutoReg: don't know how to handle: "
String -> String -> String
forall a. [a] -> [a] -> [a]
++ Type -> String
forall a. Ppr a => a -> String
pprint Type
cls String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" (" String -> String -> String
forall a. [a] -> [a] -> [a]
++ [Type] -> String
forall a. Ppr a => a -> String
pprint [Type]
tys String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
")" )
[Type]
_ -> Bool
False
recurse :: Type -> Q Cxt
recurse :: Type -> Q [Type]
recurse (Type -> (Type, [Type])
unfoldType -> (ConT Name
cls,[Type]
tys)) = Name -> [Type] -> Q [Type]
constraintsWantedFor Name
cls [Type]
tys
recurse Type
t =
String -> Q [Type]
forall (m :: Type -> Type) a. MonadFail m => String -> m a
fail (String
"Expected a class applied to some arguments but got " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Type -> String
forall a. Ppr a => a -> String
pprint Type
t)
constraintsWantedFor Name
clsNm [Type]
tys =
[Type] -> Q [Type]
forall (m :: Type -> Type) a. Monad m => a -> m a
return [Name -> [Type] -> Type
conAppsT Name
clsNm [Type]
tys]
findTyVarSubsts :: Type -> Type -> [(Name,Type)]
findTyVarSubsts :: Type -> Type -> [(Name, Type)]
findTyVarSubsts = Type -> Type -> [(Name, Type)]
go
where
go :: Type -> Type -> [(Name, Type)]
go Type
ty1 Type
ty2 = case (Type
ty1,Type
ty2) of
(VarT Name
nm1 , VarT Name
nm2) | Name
nm1 Name -> Name -> Bool
forall a. Eq a => a -> a -> Bool
== Name
nm2 -> []
(VarT Name
nm , Type
t) -> [(Name
nm,Type
t)]
(ConT Name
_ , ConT Name
_) -> []
(AppT Type
x1 Type
y1 , AppT Type
x2 Type
y2) -> Type -> Type -> [(Name, Type)]
go Type
x1 Type
x2 [(Name, Type)] -> [(Name, Type)] -> [(Name, Type)]
forall a. [a] -> [a] -> [a]
++ Type -> Type -> [(Name, Type)]
go Type
y1 Type
y2
(SigT Type
t1 Type
k1 , SigT Type
t2 Type
k2) -> Type -> Type -> [(Name, Type)]
go Type
t1 Type
t2 [(Name, Type)] -> [(Name, Type)] -> [(Name, Type)]
forall a. [a] -> [a] -> [a]
++ Type -> Type -> [(Name, Type)]
go Type
k1 Type
k2
(InfixT Type
x1 Name
_ Type
y1 , InfixT Type
x2 Name
_ Type
y2) -> Type -> Type -> [(Name, Type)]
go Type
x1 Type
x2 [(Name, Type)] -> [(Name, Type)] -> [(Name, Type)]
forall a. [a] -> [a] -> [a]
++ Type -> Type -> [(Name, Type)]
go Type
y1 Type
y2
(UInfixT Type
x1 Name
_ Type
y1, UInfixT Type
x2 Name
_ Type
y2) -> Type -> Type -> [(Name, Type)]
go Type
x1 Type
x2 [(Name, Type)] -> [(Name, Type)] -> [(Name, Type)]
forall a. [a] -> [a] -> [a]
++ Type -> Type -> [(Name, Type)]
go Type
y1 Type
y2
(ParensT Type
x1 , ParensT Type
x2) -> Type -> Type -> [(Name, Type)]
go Type
x1 Type
x2
#if __GLASGOW_HASKELL__ >= 808
(AppKindT Type
t1 Type
k1 , AppKindT Type
t2 Type
k2) -> Type -> Type -> [(Name, Type)]
go Type
t1 Type
t2 [(Name, Type)] -> [(Name, Type)] -> [(Name, Type)]
forall a. [a] -> [a] -> [a]
++ Type -> Type -> [(Name, Type)]
go Type
k1 Type
k2
(ImplicitParamT String
_ Type
x1, ImplicitParamT String
_ Type
x2) -> Type -> Type -> [(Name, Type)]
go Type
x1 Type
x2
#endif
(PromotedT Name
_ , PromotedT Name
_ ) -> []
(TupleT Int
_ , TupleT Int
_ ) -> []
(UnboxedTupleT Int
_ , UnboxedTupleT Int
_ ) -> []
(UnboxedSumT Int
_ , UnboxedSumT Int
_ ) -> []
(Type
ArrowT , Type
ArrowT ) -> []
(Type
EqualityT , Type
EqualityT ) -> []
(Type
ListT , Type
ListT ) -> []
(PromotedTupleT Int
_ , PromotedTupleT Int
_ ) -> []
(Type
PromotedNilT , Type
PromotedNilT ) -> []
(Type
PromotedConsT , Type
PromotedConsT ) -> []
(Type
StarT , Type
StarT ) -> []
(Type
ConstraintT , Type
ConstraintT ) -> []
(LitT TyLit
_ , LitT TyLit
_ ) -> []
(Type
WildCardT , Type
WildCardT ) -> []
(Type, Type)
_ -> String -> [(Name, Type)]
forall a. HasCallStack => String -> a
error (String -> [(Name, Type)]) -> String -> [(Name, Type)]
forall a b. (a -> b) -> a -> b
$ [String] -> String
unlines [ String
"findTyVarSubsts: Unexpected types"
, String
"ty1:", Type -> String
forall a. Ppr a => a -> String
pprint Type
ty1,String
"ty2:", Type -> String
forall a. Ppr a => a -> String
pprint Type
ty2]
applyTyVarSubsts :: [(Name,Type)] -> Type -> Type
applyTyVarSubsts :: [(Name, Type)] -> Type -> Type
applyTyVarSubsts [(Name, Type)]
substs Type
ty = Type -> Type
go Type
ty
where
go :: Type -> Type
go Type
ty' = case Type
ty' of
VarT Name
n -> case Name -> [(Name, Type)] -> Maybe Type
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup Name
n [(Name, Type)]
substs of
Maybe Type
Nothing -> Type
ty'
Just Type
m -> Type
m
ConT Name
_ -> Type
ty'
AppT Type
ty1 Type
ty2 -> Type -> Type -> Type
AppT (Type -> Type
go Type
ty1) (Type -> Type
go Type
ty2)
Type
_ -> String -> Type
forall a. HasCallStack => String -> a
error (String -> Type) -> String -> Type
forall a b. (a -> b) -> a -> b
$ String
"TODO applyTyVarSubsts: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Type -> String
forall a. Show a => a -> String
show Type
ty'
generateNames :: String -> [a] -> Q [Name]
generateNames :: String -> [a] -> Q [Name]
generateNames String
prefix [a]
xs =
[Q Name] -> Q [Name]
forall (t :: Type -> Type) (m :: Type -> Type) a.
(Traversable t, Monad m) =>
t (m a) -> m (t a)
sequence ((Int -> a -> Q Name) -> [Int] -> [a] -> [Q Name]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith (\Int
n a
_ -> String -> Q Name
newName (String -> Q Name) -> String -> Q Name
forall a b. (a -> b) -> a -> b
$ String
prefix String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show @Int Int
n) [Int
0..] [a]
xs)
deriveAutoRegTuples :: [Int] -> DecsQ
deriveAutoRegTuples :: [Int] -> DecsQ
deriveAutoRegTuples [Int]
xs = [[Dec]] -> [Dec]
forall (t :: Type -> Type) a. Foldable t => t [a] -> [a]
concat ([[Dec]] -> [Dec]) -> Q [[Dec]] -> DecsQ
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> (Int -> DecsQ) -> [Int] -> Q [[Dec]]
forall (t :: Type -> Type) (m :: Type -> Type) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM Int -> DecsQ
deriveAutoRegTuple [Int]
xs
deriveAutoRegTuple :: Int -> DecsQ
deriveAutoRegTuple :: Int -> DecsQ
deriveAutoRegTuple Int
n
| Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
2 = String -> DecsQ
forall (m :: Type -> Type) a. MonadFail m => String -> m a
fail (String -> DecsQ) -> String -> DecsQ
forall a b. (a -> b) -> a -> b
$ String
"deriveAutoRegTuple doesn't work for " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
n String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"-tuples"
| Bool
otherwise = Name -> DecsQ
deriveAutoReg Name
tupN
where
tupN :: Name
tupN = String -> Name
mkName (String -> Name) -> String -> Name
forall a b. (a -> b) -> a -> b
$ String
"(" String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> Char -> String
forall a. Int -> a -> [a]
replicate (Int
nInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
1) Char
',' String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
")"