{-# LANGUAGE UndecidableInstances, AllowAmbiguousTypes #-} module Godot.Internal.Dispatch where import Data.Kind import Data.Proxy import Data.Text (Text) import GHC.TypeLits as T import Godot.Gdnative.Internal.Gdnative -- | Establishes 'child` as a child of BaseClass child` class HasBaseClass child where type BaseClass child super :: child -> BaseClass child -- | Transitive subclass relation. You shouldn't need to define instances of this. class parent :< child where safeCast :: child -> parent instance {-# OVERLAPPING #-} refl :< refl where safeCast = id instance {-# OVERLAPPABLE #-} (HasBaseClass c, pp :< BaseClass c) => pp :< c where safeCast = safeCast . super -- |A class method 'name', overriden in 'cls', with signature 'sig' -- |Attempts to emulate C++/Godot's "virtual" single dispatch class Method (name :: Symbol) cls sig | cls name -> sig where runMethod :: cls -> sig instance {-# OVERLAPPABLE #-} (Method name (BaseClass child) sig, HasBaseClass child) => Method name child sig where runMethod = runMethod @name . super -- this ensures termination for type errors -- fixes #4 instance {-# OVERLAPPABLE #-} ( TypeError (T.Text "Couldn't find method " :<>: ShowType name :<>: T.Text " with signature `" :<>: ShowType sig :<>: T.Text "'.") , Method name GodotObject sig ) -- for fundeps => Method name GodotObject sig where runMethod = error "unreachable" newtype Signal a = Signal Text deriving (Show, Eq)