module Clash.Hedgehog.Core.DataCon
( genDataConsFrom
) where
import Control.Monad (replicateM, zipWithM)
import Control.Monad.Morph (hoist)
import Data.Either (partitionEithers)
import Data.Functor.Identity (Identity(runIdentity))
import Data.Text (Text)
import qualified Faker.Lorem as Fake
import Hedgehog (GenT, Range)
import qualified Hedgehog.Gen as Gen
import qualified Hedgehog.Gen.Faker as Gen
import Clash.Core.DataCon
import Clash.Core.Name
import Clash.Core.TyCon
import Clash.Core.Type
import Clash.Core.TysPrim (liftedTypeKind)
import Clash.Unique
import Clash.Hedgehog.Core.Monad
import Clash.Hedgehog.Core.Name
import Clash.Hedgehog.Core.Type
import Clash.Hedgehog.Core.Var
genDataConsFrom
:: forall m
. (Alternative m, MonadGen m)
=> Range Int
-> TyConMap
-> TyConName
-> Kind
-> CoreGenT m [DataCon]
genDataConsFrom :: Range Int -> TyConMap -> TyConName -> Kind -> CoreGenT m [DataCon]
genDataConsFrom Range Int
range TyConMap
tcm TyConName
tcn Kind
kn = do
Int
numConstructors <- [CoreGenT m Int] -> CoreGenT m Int
forall (m :: Type -> Type) a. MonadGen m => [m a] -> m a
Gen.choice [Int -> CoreGenT m Int
forall (m :: Type -> Type) a. MonadGen m => a -> m a
Gen.constant Int
1, Range Int -> CoreGenT m Int
forall (m :: Type -> Type). MonadGen m => Range Int -> m Int
Gen.int Range Int
range]
[Name DataCon]
names <- Int -> CoreGenT m (Name DataCon) -> CoreGenT m [Name DataCon]
forall (m :: Type -> Type) a.
MonadGen m =>
Int -> m (Name a) -> m [Name a]
genNames Int
numConstructors CoreGenT m (Name DataCon)
forall (m :: Type -> Type). MonadGen m => m (Name DataCon)
genDataConName
let ([TyVar]
knTvs, [Kind]
knTys) = [Either TyVar Kind] -> ([TyVar], [Kind])
forall a b. [Either a b] -> ([a], [b])
partitionEithers ([Either TyVar Kind] -> ([TyVar], [Kind]))
-> [Either TyVar Kind] -> ([TyVar], [Kind])
forall a b. (a -> b) -> a -> b
$ ([Either TyVar Kind], Kind) -> [Either TyVar Kind]
forall a b. (a, b) -> a
fst (Kind -> ([Either TyVar Kind], Kind)
splitFunForallTy Kind
kn)
[TyVar]
univTvs <- [TyVar] -> [TyVar] -> [TyVar]
forall a. Monoid a => a -> a -> a
mappend [TyVar]
knTvs ([TyVar] -> [TyVar]) -> CoreGenT m [TyVar] -> CoreGenT m [TyVar]
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> (Kind -> CoreGenT m (Name Kind) -> CoreGenT m TyVar)
-> [Kind] -> CoreGenT m (Name Kind) -> CoreGenT m [TyVar]
forall (m :: Type -> Type) a.
MonadGen m =>
(Kind -> m (Name a) -> m (Var a))
-> [Kind] -> m (Name a) -> m [Var a]
genVars Kind -> CoreGenT m (Name Kind) -> CoreGenT m TyVar
forall (m :: Type -> Type).
MonadGen m =>
Kind -> m (Name Kind) -> m TyVar
genTyVar [Kind]
knTys CoreGenT m (Name Kind)
forall (m :: Type -> Type) a. MonadGen m => m (Name a)
genVarName
[CoreGenT m [DataCon]] -> CoreGenT m [DataCon]
forall (m :: Type -> Type) a. MonadGen m => [m a] -> m a
Gen.choice
[ TyConName -> [TyVar] -> [Name DataCon] -> CoreGenT m [DataCon]
forall (m :: Type -> Type).
Applicative m =>
TyConName -> [TyVar] -> [Name DataCon] -> CoreGenT m [DataCon]
genSimpleDataCons TyConName
tcn [TyVar]
univTvs [Name DataCon]
names
, TyConMap
-> TyConName -> [TyVar] -> [Name DataCon] -> CoreGenT m [DataCon]
forall (m :: Type -> Type).
(Alternative m, MonadGen m) =>
TyConMap
-> TyConName -> [TyVar] -> [Name DataCon] -> CoreGenT m [DataCon]
genRecordDataCons TyConMap
tcm TyConName
tcn [TyVar]
univTvs [Name DataCon]
names
, TyConMap
-> TyConName -> [TyVar] -> [Name DataCon] -> CoreGenT m [DataCon]
forall (m :: Type -> Type).
(Alternative m, MonadGen m) =>
TyConMap
-> TyConName -> [TyVar] -> [Name DataCon] -> CoreGenT m [DataCon]
genAnyDataCons TyConMap
tcm TyConName
tcn [TyVar]
univTvs [Name DataCon]
names
]
genSimpleDataCons
:: forall m
. Applicative m
=> TyConName
-> [TyVar]
-> [DcName]
-> CoreGenT m [DataCon]
genSimpleDataCons :: TyConName -> [TyVar] -> [Name DataCon] -> CoreGenT m [DataCon]
genSimpleDataCons TyConName
tcn [TyVar]
univTvs =
[DataCon] -> CoreGenT m [DataCon]
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure ([DataCon] -> CoreGenT m [DataCon])
-> ([Name DataCon] -> [DataCon])
-> [Name DataCon]
-> CoreGenT m [DataCon]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Int -> Name DataCon -> DataCon)
-> [Int] -> [Name DataCon] -> [DataCon]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith Int -> Name DataCon -> DataCon
go [Int
1..]
where
go :: ConTag -> DcName -> DataCon
go :: Int -> Name DataCon -> DataCon
go Int
tag Name DataCon
name = MkData :: Name DataCon
-> Int
-> Int
-> Kind
-> [TyVar]
-> [TyVar]
-> [Kind]
-> [DcStrictness]
-> [Text]
-> DataCon
MkData
{ dcName :: Name DataCon
dcName = Name DataCon
name
, dcUniq :: Int
dcUniq = Name DataCon -> Int
forall a. Name a -> Int
nameUniq Name DataCon
name
, dcTag :: Int
dcTag = Int
tag
, dcType :: Kind
dcType = TyConName -> [Kind] -> Kind
mkTyConApp TyConName
tcn ((TyVar -> Kind) -> [TyVar] -> [Kind]
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
fmap TyVar -> Kind
VarTy [TyVar]
univTvs)
, dcUnivTyVars :: [TyVar]
dcUnivTyVars = [TyVar]
univTvs
, dcExtTyVars :: [TyVar]
dcExtTyVars = []
, dcArgTys :: [Kind]
dcArgTys = []
, dcArgStrict :: [DcStrictness]
dcArgStrict = []
, dcFieldLabels :: [Text]
dcFieldLabels = []
}
genRecordDataCons
:: forall m
. (Alternative m, MonadGen m)
=> TyConMap
-> TyConName
-> [TyVar]
-> [DcName]
-> CoreGenT m [DataCon]
genRecordDataCons :: TyConMap
-> TyConName -> [TyVar] -> [Name DataCon] -> CoreGenT m [DataCon]
genRecordDataCons TyConMap
tcm TyConName
tcn [TyVar]
univTvs =
(Int -> Name DataCon -> CoreGenT m DataCon)
-> [Int] -> [Name DataCon] -> CoreGenT m [DataCon]
forall (m :: Type -> Type) a b c.
Applicative m =>
(a -> b -> m c) -> [a] -> [b] -> m [c]
zipWithM Int -> Name DataCon -> CoreGenT m DataCon
go [Int
1..]
where
go :: ConTag -> DcName -> CoreGenT m DataCon
go :: Int -> Name DataCon -> CoreGenT m DataCon
go Int
tag Name DataCon
name = do
let resTy :: Kind
resTy = TyConName -> [Kind] -> Kind
mkTyConApp TyConName
tcn ((TyVar -> Kind) -> [TyVar] -> [Kind]
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
fmap TyVar -> Kind
VarTy [TyVar]
univTvs)
let bound :: UniqMap TyVar
bound = [(TyVar, TyVar)] -> UniqMap TyVar
forall a b. Uniquable a => [(a, b)] -> UniqMap b
listToUniqMap ([TyVar] -> [TyVar] -> [(TyVar, TyVar)]
forall a b. [a] -> [b] -> [(a, b)]
zip [TyVar]
univTvs [TyVar]
univTvs)
let argGen :: CoreGenT m Kind
argGen = TyConMap -> UniqMap TyVar -> Kind -> CoreGenT m Kind
forall (m :: Type -> Type).
(Alternative m, MonadGen m) =>
TyConMap -> UniqMap TyVar -> Kind -> CoreGenT m Kind
genMonoTypeFrom TyConMap
tcm UniqMap TyVar
bound Kind
liftedTypeKind
Kind
ty <- Kind -> CoreGenT m Kind -> CoreGenT m Kind
forall (m :: Type -> Type).
(Alternative m, MonadGen m) =>
Kind -> CoreGenT m Kind -> CoreGenT m Kind
genWithCodomain Kind
resTy CoreGenT m Kind
argGen
let ([], [Kind]
argTys) = [Either TyVar Kind] -> ([TyVar], [Kind])
forall a b. [Either a b] -> ([a], [b])
partitionEithers ([Either TyVar Kind] -> ([TyVar], [Kind]))
-> [Either TyVar Kind] -> ([TyVar], [Kind])
forall a b. (a -> b) -> a -> b
$ ([Either TyVar Kind], Kind) -> [Either TyVar Kind]
forall a b. (a, b) -> a
fst (Kind -> ([Either TyVar Kind], Kind)
splitFunForallTy Kind
ty)
[DcStrictness]
bangs <- (Kind -> CoreGenT m DcStrictness)
-> [Kind] -> CoreGenT m [DcStrictness]
forall (t :: Type -> Type) (f :: Type -> Type) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse (TyConMap -> Kind -> CoreGenT m DcStrictness
forall (m :: Type -> Type).
MonadGen m =>
TyConMap -> Kind -> m DcStrictness
genStrictness TyConMap
tcm) [Kind]
argTys
[Text]
fields <- Int -> CoreGenT m Text -> CoreGenT m [Text]
forall (m :: Type -> Type) a. Applicative m => Int -> m a -> m [a]
replicateM ([Kind] -> Int
forall (t :: Type -> Type) a. Foldable t => t a -> Int
length [Kind]
argTys) CoreGenT m Text
forall (m :: Type -> Type). MonadGen m => m Text
genFieldLabel
DataCon -> CoreGenT m DataCon
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure MkData :: Name DataCon
-> Int
-> Int
-> Kind
-> [TyVar]
-> [TyVar]
-> [Kind]
-> [DcStrictness]
-> [Text]
-> DataCon
MkData
{ dcName :: Name DataCon
dcName = Name DataCon
name
, dcUniq :: Int
dcUniq = Name DataCon -> Int
forall a. Name a -> Int
nameUniq Name DataCon
name
, dcTag :: Int
dcTag = Int
tag
, dcType :: Kind
dcType = Kind
ty
, dcUnivTyVars :: [TyVar]
dcUnivTyVars = [TyVar]
univTvs
, dcExtTyVars :: [TyVar]
dcExtTyVars = []
, dcArgTys :: [Kind]
dcArgTys = [Kind]
argTys
, dcArgStrict :: [DcStrictness]
dcArgStrict = [DcStrictness]
bangs
, dcFieldLabels :: [Text]
dcFieldLabels = [Text]
fields
}
genAnyDataCons
:: forall m
. (Alternative m, MonadGen m)
=> TyConMap
-> TyConName
-> [TyVar]
-> [DcName]
-> CoreGenT m [DataCon]
genAnyDataCons :: TyConMap
-> TyConName -> [TyVar] -> [Name DataCon] -> CoreGenT m [DataCon]
genAnyDataCons TyConMap
tcm TyConName
tcn [TyVar]
univTvs =
(Int -> Name DataCon -> CoreGenT m DataCon)
-> [Int] -> [Name DataCon] -> CoreGenT m [DataCon]
forall (m :: Type -> Type) a b c.
Applicative m =>
(a -> b -> m c) -> [a] -> [b] -> m [c]
zipWithM Int -> Name DataCon -> CoreGenT m DataCon
go [Int
1..]
where
go :: ConTag -> DcName -> CoreGenT m DataCon
go :: Int -> Name DataCon -> CoreGenT m DataCon
go Int
tag Name DataCon
name = do
let resTy :: Kind
resTy = TyConName -> [Kind] -> Kind
mkTyConApp TyConName
tcn ((TyVar -> Kind) -> [TyVar] -> [Kind]
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
fmap TyVar -> Kind
VarTy [TyVar]
univTvs)
let bound :: UniqMap TyVar
bound = [(TyVar, TyVar)] -> UniqMap TyVar
forall a b. Uniquable a => [(a, b)] -> UniqMap b
listToUniqMap ([TyVar] -> [TyVar] -> [(TyVar, TyVar)]
forall a b. [a] -> [b] -> [(a, b)]
zip [TyVar]
univTvs [TyVar]
univTvs)
let argGen :: CoreGenT m Kind
argGen = TyConMap -> UniqMap TyVar -> Kind -> CoreGenT m Kind
forall (m :: Type -> Type).
(Alternative m, MonadGen m) =>
TyConMap -> UniqMap TyVar -> Kind -> CoreGenT m Kind
genMonoTypeFrom TyConMap
tcm UniqMap TyVar
bound Kind
liftedTypeKind
Kind
ty <- Kind -> CoreGenT m Kind -> CoreGenT m Kind
forall (m :: Type -> Type).
(Alternative m, MonadGen m) =>
Kind -> CoreGenT m Kind -> CoreGenT m Kind
genWithCodomain Kind
resTy CoreGenT m Kind
argGen
let ([TyVar]
extTvs, [Kind]
argTys) = [Either TyVar Kind] -> ([TyVar], [Kind])
forall a b. [Either a b] -> ([a], [b])
partitionEithers ([Either TyVar Kind] -> ([TyVar], [Kind]))
-> [Either TyVar Kind] -> ([TyVar], [Kind])
forall a b. (a -> b) -> a -> b
$ ([Either TyVar Kind], Kind) -> [Either TyVar Kind]
forall a b. (a, b) -> a
fst (Kind -> ([Either TyVar Kind], Kind)
splitFunForallTy Kind
ty)
[DcStrictness]
bangs <- (Kind -> CoreGenT m DcStrictness)
-> [Kind] -> CoreGenT m [DcStrictness]
forall (t :: Type -> Type) (f :: Type -> Type) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse (TyConMap -> Kind -> CoreGenT m DcStrictness
forall (m :: Type -> Type).
MonadGen m =>
TyConMap -> Kind -> m DcStrictness
genStrictness TyConMap
tcm) [Kind]
argTys
DataCon -> CoreGenT m DataCon
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure MkData :: Name DataCon
-> Int
-> Int
-> Kind
-> [TyVar]
-> [TyVar]
-> [Kind]
-> [DcStrictness]
-> [Text]
-> DataCon
MkData
{ dcName :: Name DataCon
dcName = Name DataCon
name
, dcUniq :: Int
dcUniq = Name DataCon -> Int
forall a. Name a -> Int
nameUniq Name DataCon
name
, dcTag :: Int
dcTag = Int
tag
, dcType :: Kind
dcType = Kind
ty
, dcUnivTyVars :: [TyVar]
dcUnivTyVars = [TyVar]
univTvs
, dcExtTyVars :: [TyVar]
dcExtTyVars = [TyVar]
extTvs
, dcArgTys :: [Kind]
dcArgTys = [Kind]
argTys
, dcArgStrict :: [DcStrictness]
dcArgStrict = [DcStrictness]
bangs
, dcFieldLabels :: [Text]
dcFieldLabels = []
}
genStrictness
:: forall m. MonadGen m => TyConMap -> Kind -> m DcStrictness
genStrictness :: TyConMap -> Kind -> m DcStrictness
genStrictness TyConMap
tcm Kind
kn
| TyConApp TyConName
tc [] <- Kind -> TypeView
tyView Kind
kn
, Just PrimTyCon{} <- TyConName -> TyConMap -> Maybe TyCon
forall a b. Uniquable a => a -> UniqMap b -> Maybe b
lookupUniqMap TyConName
tc TyConMap
tcm
= DcStrictness -> m DcStrictness
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure DcStrictness
Strict
| Bool
otherwise
= [DcStrictness] -> m DcStrictness
forall (m :: Type -> Type) a. MonadGen m => [a] -> m a
Gen.element [DcStrictness
Lazy, DcStrictness
Strict]
genFieldLabel :: forall m. MonadGen m => m Text
genFieldLabel :: m Text
genFieldLabel =
GenT (GenBase m) Text -> m Text
forall (m :: Type -> Type) a.
MonadGen m =>
GenT (GenBase m) a -> m a
fromGenT (GenT (GenBase m) Text -> m Text)
-> GenT (GenBase m) Text -> m Text
forall a b. (a -> b) -> a -> b
$ (forall a. Identity a -> GenBase m a)
-> GenT Identity Text -> GenT (GenBase m) Text
forall k (t :: (Type -> Type) -> k -> Type) (m :: Type -> Type)
(n :: Type -> Type) (b :: k).
(MFunctor t, Monad m) =>
(forall a. m a -> n a) -> t m b -> t n b
hoist @GenT @Identity @(GenBase m)
(a -> GenBase m a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure (a -> GenBase m a)
-> (Identity a -> a) -> Identity a -> GenBase m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Identity a -> a
forall a. Identity a -> a
runIdentity)
(Fake Text -> GenT Identity Text
forall a. Fake a -> Gen a
Gen.fake Fake Text
Fake.words)