packages feed

constraints-deriving-1.1.1.2: src/Data/Constraint/Deriving/OverlapMode.hs

{-# LANGUAGE CPP                 #-}
{-# LANGUAGE DeriveDataTypeable  #-}
module Data.Constraint.Deriving.OverlapMode
  ( OverlapMode (..)
  , toOverlapFlag, instanceOverlapMode
  ) where

import           Data.Data           (Data)
import           Data.Semigroup      as Sem (Semigroup (..))
import           Data.Monoid         as Mon (Monoid (..))

#if __GLASGOW_HASKELL__ >= 900
import qualified GHC.Types.Basic as BasicTypes
import qualified GHC.Core.InstEnv as InstEnv
#else
import qualified BasicTypes
import qualified InstEnv
#endif

-- | Define the behavior for the instance selection.
--   Mirrors `BasicTypes.OverlapMode`, but does not have a `SourceText` field.
data OverlapMode
  = NoOverlap
    -- ^ This instance must not overlap another `NoOverlap` instance.
    --   However, it may be overlapped by `Overlapping` instances,
    --   and it may overlap `Overlappable` instances.
  | Overlappable
    -- ^ Silently ignore this instance if you find a
    --   more specific one that matches the constraint
    --   you are trying to resolve
  | Overlapping
    -- ^ Silently ignore any more general instances that may be
    --   used to solve the constraint.
  | Overlaps
    -- ^ Equivalent to having both `Overlapping` and `Overlappable` flags.
  | Incoherent
    -- ^ Behave like Overlappable and Overlapping, and in addition pick
    --   an an arbitrary one if there are multiple matching candidates, and
    --   don't worry about later instantiation
  deriving (Eq, Show, Read, Data)

instance Sem.Semigroup OverlapMode where
    NoOverlap <> m = m
    m <> NoOverlap = m
    Incoherent <> _ = Incoherent
    _ <> Incoherent = Incoherent
    Overlaps <> _   = Overlaps
    _ <> Overlaps   = Overlaps
    Overlappable <> Overlappable = Overlappable
    Overlapping  <> Overlapping  = Overlapping
    Overlappable <> Overlapping  = Overlaps
    Overlapping  <> Overlappable = Overlaps

instance Mon.Monoid OverlapMode where
    mempty = NoOverlap
#if !(MIN_VERSION_base(4,11,0))
    mappend = (<>)
#endif


toOverlapFlag :: OverlapMode -> BasicTypes.OverlapFlag
toOverlapFlag m = BasicTypes.OverlapFlag (getOMode m) False
  where
    getOMode NoOverlap    = BasicTypes.NoOverlap noSourceText
    getOMode Overlapping  = BasicTypes.Overlapping noSourceText
    getOMode Overlappable = BasicTypes.Overlappable noSourceText
    getOMode Overlaps     = BasicTypes.Overlaps noSourceText
    getOMode Incoherent   = BasicTypes.Incoherent noSourceText

#if __GLASGOW_HASKELL__ >= 802
    noSourceText = BasicTypes.NoSourceText
#else
    noSourceText = "[plugin-generated code]"
#endif

instanceOverlapMode :: InstEnv.ClsInst -> OverlapMode
instanceOverlapMode i = case BasicTypes.overlapMode (InstEnv.is_flag i) of
    BasicTypes.NoOverlap {}    -> NoOverlap
    BasicTypes.Overlapping {}  -> Overlapping
    BasicTypes.Overlappable {} -> Overlappable
    BasicTypes.Overlaps {}     -> Overlaps
    BasicTypes.Incoherent {}   -> Incoherent