{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}
{-# OPTIONS_GHC -fno-warn-simplifiable-class-constraints #-}

{-# LANGUAGE DataKinds #-}

-- | This module helps to visualize and debug the 'BuiltinMeaning' inference machinery from the
-- @Elaborate@ and @Meaning@ modules.
module PlutusCore.Builtin.Debug
  ( elaborateDebug
  , makeBuiltinMeaningDebug
  -- Reexporting a bunch of stuff, so that debug output is not littered with module names.
  , module Export
  ) where

import PlutusCore.Builtin.Elaborate as Export
import PlutusCore.Builtin.Meaning as Export
import PlutusCore.Builtin.Polymorphism as Export
import PlutusCore.Core as Export
import PlutusCore.Default as Export
import PlutusCore.Name.Unique as Export

-- | Instantiate type variables in the type of a value using 'ElaborateFromTo'. Example usages:
--
-- >>> :t elaborateDebug False
-- elaborateDebug False :: Bool
-- >>> :t elaborateDebug fst
-- elaborateDebug fst
--   :: (TyVarRep ('TyNameRep "a" 0), TyVarRep ('TyNameRep "b" 1))
--      -> TyVarRep ('TyNameRep "a" 0)
elaborateDebug
    :: forall a j. ElaborateFromTo DefaultUni 0 j (Term TyName Name DefaultUni DefaultFun ()) a
    => a -> a
elaborateDebug :: forall a (j :: Nat).
ElaborateFromTo
  DefaultUni 0 j (Term TyName Name DefaultUni DefaultFun ()) a =>
a -> a
elaborateDebug = a -> a
forall a. a -> a
id

-- >>> :t makeBuiltinMeaningDebug $ \_ -> ()
-- makeBuiltinMeaningDebug $ \_ -> ()
--   :: Opaque
--        (Term TyName Name DefaultUni DefaultFun ())
--        (TyVarRep ('TyNameRep "a" 0))
--      -> ()
-- >>> :t makeBuiltinMeaningDebug False
-- <interactive>:1:1: error:
--     • A built-in function must take at least one type or term argument
--       ‘Bool’ is a built-in type so you can embed any of its values as a constant
--       If you still want a built-in function, add a dummy ‘()’ argument
--     • In the expression: makeBuiltinMeaningDebug False
-- >>> :t makeBuiltinMeaningDebug $ 0 + 42
-- <interactive>:1:29: error:
--     • Built-in functions are not allowed to have constraints
--       To fix this error instantiate all constrained type variables
--     • In the second argument of ‘($)’, namely ‘0 + 42’
--       In the expression: makeBuiltinMeaningDebug $ 0 + 42
-- >>> :t makeBuiltinMeaningDebug $ Just ()
-- <interactive>:1:1: error:
--     • No instance for ‘KnownTypeAst DefaultUni (Maybe ())’
--       Which means
--         ‘Maybe ()’
--       is neither a built-in type, nor one of the control types.
--       If it can be represented in terms of one of the built-in types
--         then go add the instance (you may need a few others too)
--         alongside the instance for the built-in type.
--       Otherwise you may need to add a new built-in type
--         (provided you're doing something that can be supported in principle)
--     • In the first argument of ‘($)’, namely ‘makeBuiltinMeaningDebug’
--       In the expression: makeBuiltinMeaningDebug $ Just ()
-- >>> :t makeBuiltinMeaningDebug fst
-- <interactive>:1:1: error:
--     • An unwrapped built-in type constructor can't be applied to a type variable
--       Are you trying to define a polymorphic built-in function over a polymorphic type?
--       In that case you need to wrap all polymorphic built-in types applied to type
--        variables with either ‘SomeConstant’ or ‘Opaque’ depending on whether its the
--        type of an argument or the type of the result, respectively
--     • In the expression: makeBuiltinMeaningDebug fst
-- >>> :t makeBuiltinMeaningDebug null
-- <interactive>:1:1: error:
--     • A built-in function is not allowed to have applied type variables in its type
--       To fix this error specialize all higher-kinded type variables
--     • In the expression: makeBuiltinMeaningDebug null
-- >>> :t makeBuiltinMeaningDebug (undefined :: Opaque val (f Bool) -> ())
-- <interactive>:1:1: error:
--     • No instance for ‘KnownTypeAst DefaultUni (TyVarRep
--                                                   ('TyNameRep "f" 0) Bool)’
--       Which means
--         ‘TyVarRep ('TyNameRep "f" 0) Bool’
--       is neither a built-in type, nor one of the control types.
--       If it can be represented in terms of one of the built-in types
--         then go add the instance (you may need a few others too)
--         alongside the instance for the built-in type.
--       Otherwise you may need to add a new built-in type
--         (provided you're doing something that can be supported in principle)
--     • In the expression:
--         makeBuiltinMeaningDebug (undefined :: Opaque val (f Bool) -> ())
-- <interactive>:1:1: error:
--     • A built-in function is not allowed to have applied type variables in its type
--       To fix this error apply type variables via explicit ‘TyAppRep’
--     • In the expression:
--         makeBuiltinMeaningDebug (undefined :: Opaque val (f Bool) -> ())
makeBuiltinMeaningDebug
    :: forall a. MakeBuiltinMeaning a (Term TyName Name DefaultUni DefaultFun ())
    => a -> a
makeBuiltinMeaningDebug :: forall a.
MakeBuiltinMeaning a (Term TyName Name DefaultUni DefaultFun ()) =>
a -> a
makeBuiltinMeaningDebug = a -> a
forall a. a -> a
id