intensional-datatys-0.2.0.0: src/Intensional/Constructors.hs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE LambdaCase #-}
-- The Hashable instances for Unique and Name are orphans
-- but should eventually be removed when hashtables are
-- replaced in the ConstraintSet representation.
{-# OPTIONS_GHC -Wno-orphans #-}
module Intensional.Constructors
( Side (..),
K (..),
ConL,
ConR,
toAtomic,
getLocation
)
where
import Binary
import Data.Hashable
import GhcPlugins hiding (L)
import Intensional.Types
import Unique
instance Hashable Unique where
hashWithSalt s = hashWithSalt s . getKey
instance Hashable Name where
hashWithSalt s = hashWithSalt s . getUnique
data Side = L | R
-- A constructor set with a location tag
-- We include the srcSpan as part of the
-- identity so that multiple errors with
-- the same constructor in different program
-- locations are treated seperately.
data K (s :: Side) where
Dom :: DataType Name -> K s
Con :: Name -> SrcSpan -> K 'L
Set :: UniqSet Name -> SrcSpan -> K 'R
type ConL = K 'L
type ConR = K 'R
-- Don't disregard location in comparison
-- i.e. distinguish between different sources
-- and sinks
instance Eq (K s) where
Dom d == Dom d' = d == d'
Con k l == Con k' l' = k == k' && l == l'
Set s l == Set s' l' = s == s' && l == l'
_ == _ = False
instance Hashable (K s) where
hashWithSalt s (Dom d) = hashWithSalt s d
hashWithSalt s (Con k _) = hashWithSalt s k
hashWithSalt s (Set ks _) = hashWithSalt s (nonDetKeysUniqSet ks)
instance Outputable (K s) where
ppr = prpr ppr
instance Binary (K 'L) where
put_ bh (Dom d) = put_ bh False >> put_ bh d
put_ bh (Con k l) = put_ bh True >> put_ bh k >> put_ bh l
get bh =
get bh >>= \case
False -> Dom <$> get bh
True -> Con <$> get bh <*> get bh
instance Binary (K 'R) where
put_ bh (Dom d) = put_ bh False >> put_ bh d
put_ bh (Set s l) = put_ bh True >> put_ bh (nonDetEltsUniqSet s) >> put_ bh l
get bh =
get bh >>= \case
False -> Dom <$> get bh
True -> do
s <- mkUniqSet <$> get bh
l <- get bh
return (Set s l)
instance Refined (K l) where
domain (Dom d) = domain d
domain _ = mempty
rename x y (Dom d) = Dom (rename x y d)
rename _ _ s = s
prpr m (Dom (Inj x d)) = m x GhcPlugins.<> parens (ppr d)
prpr _ (Dom (Base _)) = error "Base in constraint."
prpr _ (Con k _) = ppr k
prpr _ (Set ks _) = hcat [char '{', pprWithBars ppr (nonDetEltsUniqSet ks), char '}']
{-|
Assuming @k@ is either a @Con@ or @Set@ atom,
@getLocation k@ is the associated span.
-}
getLocation :: K a -> SrcSpan
getLocation (Con _ s) = s
getLocation (Set _ s) = s
getLocation _ = error "Dom constructors have no location."
-- Convert constraint to atomic form
toAtomic :: K l -> K r -> [(K 'L, K 'R)]
toAtomic (Dom d) (Dom d')
| d == d' = []
| otherwise = [(Dom d, Dom d')]
toAtomic (Dom d) (Con k l) =
[(Dom d, Set (unitUniqSet k) l)]
toAtomic (Dom d) (Set ks l) =
[(Dom d, Set ks l)]
toAtomic (Con k l) (Dom d) =
[(Con k l, Dom d)]
toAtomic (Con k l) (Con k' l')
| k == k' = []
| otherwise = [(Con k l, Set emptyUniqSet l')]
toAtomic (Con k l) (Set ks l')
| elementOfUniqSet k ks = []
| otherwise = [(Con k l, Set emptyUniqSet l')]
toAtomic (Set ks l) (Dom d) =
[(Con k l, Dom d) | k <- nonDetEltsUniqSet ks]
toAtomic (Set ks l) (Con k l') =
[(Con k l, Set emptyUniqSet l') | k' <- nonDetEltsUniqSet ks, k' /= k]
toAtomic (Set ks l) (Set ks' l') =
[(Con k l, Set emptyUniqSet l') | k <- nonDetEltsUniqSet ks, not (elementOfUniqSet k ks')]