Created
July 15, 2019 12:30
-
-
Save martijnbastiaan/37e959588e347d8b5b9142434eb8f4e7 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{-# LANGUAGE CPP #-} | |
{-# LANGUAGE ConstraintKinds #-} | |
{-# LANGUAGE DataKinds #-} | |
{-# LANGUAGE FlexibleInstances #-} | |
{-# LANGUAGE TypeFamilies #-} | |
{-# LANGUAGE TypeOperators #-} | |
{-# LANGUAGE UndecidableInstances #-} | |
#if __GLASGOW_HASKELL__ < 806 | |
{-# LANGUAGE TypeInType #-} | |
#endif | |
{-# OPTIONS_GHC -Wno-missing-methods #-} | |
module Clash.Class.HasDomain.HasSingleDomain | |
( HasSingleDomain(..) ) where | |
import Clash.Class.HasDomain.Common | |
import Clash.Sized.Vector (Vec) | |
import Clash.Sized.RTree (RTree) | |
import Clash.Signal.Internal | |
(Signal, Domain, Clock, Reset, Enable) | |
import Clash.Signal.Delayed.Internal (DSignal) | |
import Data.Proxy (Proxy) | |
import Data.Type.Bool (type If, type (&&)) | |
import Data.Type.Equality (type (==)) | |
import Type.Errors (TypeError, ErrorMessage(Text)) | |
data TryDomainResult | |
= NotFound | |
| Ambiguous | |
| Found Domain | |
-- | Type family to resolve type conflicts (if any) | |
type family MergeTryDomainResults (n :: TryDomainResult) (m :: TryDomainResult) :: TryDomainResult where | |
MergeTryDomainResults n m = | |
If (n == 'NotFound && m == 'NotFound) | |
'NotFound | |
(If (n == m) | |
(n) | |
(If (n == 'NotFound) | |
(m) | |
(If (m == 'NotFound) | |
n | |
'Ambiguous))) | |
type family ErrOnConflict (n :: TryDomainResult) :: Domain where | |
ErrOnConflict 'NotFound = TypeError ('Text "foo!") | |
ErrOnConflict 'Ambiguous = TypeError ('Text "bar!") | |
ErrOnConflict ('Found dom) = dom | |
type family TryDomain n :: TryDomainResult where | |
TryDomain (DSignal dom delay a) = 'Found dom | |
TryDomain (Signal dom a) = 'Found dom | |
TryDomain (Clock dom) = 'Found dom | |
TryDomain (Reset dom) = 'Found dom | |
TryDomain (Enable dom) = 'Found dom | |
TryDomain (a -> b) = MergeTryDomainResults (TryDomain a) (TryDomain b) | |
TryDomain (Vec n a) = TryDomain a | |
TryDomain (a, b) = MergeTryDomainResults (TryDomain a) (TryDomain b) | |
TryDomain a = 'NotFound | |
class HasSingleDomain r where | |
type GetDomain r :: Domain | |
instance {-# OVERLAPPABLE #-} TypeError NoHasDomainInstance => HasSingleDomain a | |
instance HasSingleDomain (DSignal dom delay a) where | |
type GetDomain (DSignal dom delay a) = dom | |
instance HasSingleDomain (Signal dom a) where | |
type GetDomain (Signal dom a) = dom | |
instance HasSingleDomain (a -> b) where | |
type GetDomain (a -> b) = | |
ErrOnConflict (MergeTryDomainResults (TryDomain a) (TryDomain b)) | |
instance HasSingleDomain (Vec n a) where | |
type GetDomain (Vec n a) = ErrOnConflict (TryDomain a) | |
instance HasSingleDomain (RTree d a) where | |
type GetDomain (RTree d a) = ErrOnConflict (TryDomain a) | |
instance HasSingleDomain (a, b) where | |
type GetDomain (a, b) = | |
ErrOnConflict (MergeTryDomainResults (TryDomain a) (TryDomain b)) | |
instance HasSingleDomain (Proxy (dom :: Domain)) where | |
type GetDomain (Proxy dom) = dom | |
instance HasSingleDomain (Clock dom) where | |
type GetDomain (Clock dom) = dom | |
instance HasSingleDomain (Reset dom) where | |
type GetDomain (Reset dom) = dom | |
instance HasSingleDomain (Enable dom) where | |
type GetDomain (Enable dom) = dom |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment