{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_HADDOCK not-home #-}
module Polysemy.Internal.CustomErrors
( AmbiguousSend
, WhenStuck
, FirstOrder
, UnhandledEffect
, DefiningModule
, DefiningModuleForEffect
, type (<>)
, type (%)
) where
import Data.Kind
import Fcf
import GHC.TypeLits (Symbol)
import Polysemy.Internal.Kind
import Polysemy.Internal.CustomErrors.Redefined
import Type.Errors hiding (IfStuck, WhenStuck, UnlessStuck)
type family DefiningModule (t :: k) :: Symbol
type family DefiningModuleForEffect (e :: k) :: Symbol where
DefiningModuleForEffect (e a) = DefiningModuleForEffect e
DefiningModuleForEffect e = DefiningModule e
type family ToErrorMessage (t :: k) :: ErrorMessage where
ToErrorMessage (t :: Symbol) = 'Text t
ToErrorMessage (t :: ErrorMessage) = t
ToErrorMessage t = 'ShowType t
infixl 5 <>
type family (<>) (l :: k1) (r :: k2) :: ErrorMessage where
l <> r = ToErrorMessage l ':<>: ToErrorMessage r
infixr 4 %
type family (%) (t :: k1) (b :: k2) :: ErrorMessage where
t % b = ToErrorMessage t ':$$: ToErrorMessage b
type ShowTypeBracketed t = "(" <> t <> ")"
data EffectRowCtor = TyVarR | NilR | ConsR
type family UnstuckRState (r :: EffectRow) :: EffectRowCtor where
UnstuckRState '[] = 'NilR
UnstuckRState (_ ': _) = 'ConsR
type family ShowRQuoted (rstate :: EffectRowCtor) (r :: EffectRow) :: ErrorMessage where
ShowRQuoted 'TyVarR r = 'ShowType r
ShowRQuoted 'NilR r = 'ShowType r
ShowRQuoted 'ConsR r = ShowTypeBracketed r
type AmbigousEffectMessage (rstate :: EffectRowCtor)
(r :: EffectRow)
(e :: k)
(t :: Effect)
(vs :: [Type])
= "Ambiguous use of effect '" <> e <> "'"
% "Possible fix:"
% " add (Member (" <> t <> ") " <> ShowRQuoted rstate r <> ") to the context of "
% " the type signature"
% "If you already have the constraint you want, instead"
% " add a type application to specify"
% " " <> PrettyPrintList vs <> " directly, or activate polysemy-plugin which"
% " can usually infer the type correctly."
type AmbiguousSend e r =
(IfStuck r
(AmbiguousSendError 'TyVarR r e)
(Pure (AmbiguousSendError (UnstuckRState r) r e)))
type family AmbiguousSendError rstate r e where
AmbiguousSendError rstate r (e a b c d f) =
TypeError (AmbigousEffectMessage rstate r e (e a b c d f) '[a, b c d f])
AmbiguousSendError rstate r (e a b c d) =
TypeError (AmbigousEffectMessage rstate r e (e a b c d) '[a, b c d])
AmbiguousSendError rstate r (e a b c) =
TypeError (AmbigousEffectMessage rstate r e (e a b c) '[a, b c])
AmbiguousSendError rstate r (e a b) =
TypeError (AmbigousEffectMessage rstate r e (e a b) '[a, b])
AmbiguousSendError rstate r (e a) =
TypeError (AmbigousEffectMessage rstate r e (e a) '[a])
AmbiguousSendError rstate r e =
TypeError
( "Could not deduce: (Member " <> e <> " " <> ShowRQuoted rstate r <> ") "
% "Fix:"
% " add (Member " <> e <> " " <> r <> ") to the context of"
% " the type signature"
)
data FirstOrderErrorFcf :: k -> Symbol -> Exp Constraint
type instance Eval (FirstOrderErrorFcf e fn) = $(te[t|
UnlessPhantom
(e PHANTOM)
( "'" <> e <> "' is higher-order, but '" <> fn <> "' can help only"
% "with first-order effects."
% "Fix:"
% " use '" <> fn <> "H' instead."
) |])
type FirstOrder (e :: Effect) fn = UnlessStuck e (FirstOrderErrorFcf e fn)
type UnhandledEffectMsg e
= "Unhandled effect '" <> e <> "'"
% "Probable fix:"
% " add an interpretation for '" <> e <> "'"
type CheckDocumentation e
= " If you are looking for inspiration, try consulting"
% " the documentation for module '" <> DefiningModuleForEffect e <> "'"
type family UnhandledEffect e where
UnhandledEffect e =
IfStuck (DefiningModule e)
(TypeError (UnhandledEffectMsg e))
(DoError (UnhandledEffectMsg e ':$$: CheckDocumentation e))
data DoError :: ErrorMessage -> Exp k
type instance Eval (DoError a) = TypeError a