{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE StandaloneKindSignatures #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
module PlutusCore.Builtin.Elaborate
( ElaborateFromTo
) where
import PlutusCore.Builtin.KnownTypeAst
import PlutusCore.Builtin.Polymorphism
import PlutusCore.Core.Type
import Data.Kind qualified as GHC
import Data.Type.Bool
import Data.Type.Equality
import GHC.TypeLits
type (===) :: forall a b. a -> b -> Bool
type family x === y where
x === x = 'True
x === y = 'False
type TryUnify :: forall a b. Bool -> a -> b -> GHC.Constraint
class same ~ (x === y) => TryUnify same x y
instance (x === y) ~ 'False => TryUnify 'False x y
instance {-# INCOHERENT #-} (x ~~ y, same ~ 'True) => TryUnify same x y
type (~?~) :: forall a b. a -> b -> GHC.Constraint
type x ~?~ y = TryUnify (x === y) x y
type Lookup :: forall a. Nat -> [a] -> a
type family Lookup n xs where
Lookup _ '[] = TypeError ('Text "Not enough elements")
Lookup 0 (x ': xs) = x
Lookup n (_ ': xs) = Lookup (n - 1) xs
type GetName :: GHC.Type -> Nat -> Symbol
type family GetName k i where
GetName GHC.Type i = Lookup i '["a", "b", "c", "d", "e", "i", "j", "k", "l"]
GetName _ i = Lookup i '["f", "g", "h", "m", "n"]
type Id :: forall a. a -> a
data family Id x
type TrySpecializeAsVar :: forall k. Nat -> Nat -> (k -> k) -> k -> GHC.Constraint
class TrySpecializeAsVar i j f a | i f a -> j
instance
( var ~ f (TyVarRep @k ('TyNameRep (GetName k i) i))
, a ~?~ var
, j ~ If (a === var) (i + 1) i
) => TrySpecializeAsVar i j f (a :: k)
type HandleHole :: Nat -> Nat -> GHC.Type -> Hole -> GHC.Constraint
class HandleHole i j val hole | i val hole -> j
instance
( TrySpecializeAsVar i j Id (Id x)
, HandleHoles j k val x
) => HandleHole i k val (RepHole x)
instance
( TrySpecializeAsVar i j (Opaque val) a
, HandleHoles j k val a
) => HandleHole i k val (TypeHole a)
type HandleHolesGo :: Nat -> Nat -> GHC.Type -> [Hole] -> GHC.Constraint
class HandleHolesGo i j val holes | i val holes -> j
instance i ~ j => HandleHolesGo i j val '[]
instance
( HandleHole i j val hole
, HandleHolesGo j k val holes
) => HandleHolesGo i k val (hole ': holes)
type ThrowOnStuckList :: forall a. [a] -> [a] -> [a]
type family ThrowOnStuckList err xs where
ThrowOnStuckList _ '[] = '[]
ThrowOnStuckList _ (x ': xs) = x ': xs
ThrowOnStuckList err _ = err
type UnknownTypeError :: forall a any. GHC.Type -> a -> any
type family UnknownTypeError val x where
UnknownTypeError val x = TypeError
( 'Text "No instance for ‘KnownTypeAst "
':<>: 'ShowType (UniOf val)
':<>: 'Text " ("
':<>: 'ShowType x
':<>: 'Text ")’"
':$$: 'Text "Which means"
':$$: 'Text " ‘" ':<>: 'ShowType x ':<>: 'Text "’"
':$$: 'Text "is neither a built-in type, nor one of the control types."
':$$: 'Text "If it can be represented in terms of one of the built-in types"
':$$: 'Text " then go add the instance (you may need a ‘KnownTypeIn’ one too)"
':$$: 'Text " alongside the instance for the built-in type."
':$$: 'Text "Otherwise you may need to add a new built-in type"
':$$: 'Text " (provided you're doing something that can be supported in principle)"
)
type HandleHoles :: forall a. Nat -> Nat -> GHC.Type -> a -> GHC.Constraint
type HandleHoles i j val x =
HandleHolesGo i j val (ThrowOnStuckList (UnknownTypeError val x) (ToHoles x))
type ElaborateFromTo :: Nat -> Nat -> GHC.Type -> GHC.Type -> GHC.Constraint
type ElaborateFromTo i j val a = HandleHole i j val (TypeHole a)