packages feed

exference-1.6.0.0: src/Language/Haskell/Exference/Core/Internal/ConstraintSolver.hs

{-# LANGUAGE MonadComprehensions #-}

module Language.Haskell.Exference.Core.Internal.ConstraintSolver
  ( isPossible
  , filterUnresolved
  )
where



import Language.Haskell.Exference.Core.Types
import Language.Haskell.Exference.Core.TypeUtils
import Language.Haskell.Exference.Core.Internal.Unify

import qualified Data.Set as S
import Control.Monad ( mplus, guard, join )
import Control.Applicative ( (<|>), (<$>), liftA2 )
import Data.Foldable ( asum )
import Data.Maybe ( fromMaybe )
import Data.Traversable ( traverse )

import qualified Data.Map.Strict as M
import qualified Data.IntMap.Strict as IntMap

import Debug.Trace



-- returns Nothing if one of the constraints is refutable
-- otherwise Just a list of open constraints (that could neither be
-- solved nor refuted).
isPossible :: QueryClassEnv -> [HsConstraint] -> Maybe [HsConstraint]
isPossible = checkPossibleGeneric (Just . return) (const Nothing)

-- returns Nothing if any of the constraints contains variables
-- (as variables cannot be proven).
-- Otherwise returns the list of constraints that cannot be proven,
-- and removing all those that can be proven.
filterUnresolved :: QueryClassEnv -> [HsConstraint] -> Maybe [HsConstraint]
filterUnresolved = checkPossibleGeneric (const Nothing) (Just . return)

checkPossibleGeneric :: (HsConstraint -> Maybe [HsConstraint])
                     -> (HsConstraint -> Maybe [HsConstraint])
                     -> QueryClassEnv
                     -> [HsConstraint]
                     -> Maybe [HsConstraint]
checkPossibleGeneric containsVarsResult otherwiseResult qClassEnv = fmap concat . traverse g where
  g c = if constraintContainsVariables c
    then containsVarsResult c
    else possibleFromGiven c <|> possibleFromInstance c <|> otherwiseResult c
  possibleFromGiven :: HsConstraint -> Maybe [HsConstraint]
  possibleFromGiven c = [ [] | S.member c $ qClassEnv_inflatedConstraints qClassEnv ]
  possibleFromInstance :: HsConstraint -> Maybe [HsConstraint]
  possibleFromInstance c = asum $ f <$> is where
    (HsConstraint cclass cparams) = c
    is = M.findWithDefault []
                           (tclass_name cclass)
                           ( sClassEnv_instances
                             $ qClassEnv_env qClassEnv )
    f (HsInstance instConstrs _iclass instParams) = do
      substs <- unifyRightEqs $ zipWith TypeEq cparams instParams
      checkPossibleGeneric containsVarsResult otherwiseResult
        qClassEnv
        (map (snd . constraintApplySubsts substs) instConstrs)