packages feed

haskell-tools-builtin-refactorings-1.0.1.1: Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/GADTsChecker.hs

module Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.Checkers.GADTsChecker where

import Data.Maybe (catMaybes, fromMaybe)
import Control.Reference ((^.), (&))
import Control.Monad.Trans.Maybe (MaybeT(..))

import Language.Haskell.Tools.AST
import Language.Haskell.Tools.Refactor
import Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.ExtMonad


-- | Checks a GADT-style constructor if GADTSyntax is turned on.
-- Sometimes GADTSyntax is sufficient and GADTs is not even needed.
chkGADTsGadtConDecl :: CheckNode GadtConDecl
chkGADTsGadtConDecl = conditional chkGADTsGadtConDecl' GADTSyntax

-- | Checks a data constructor declaration if GADTs or ExistentialQuantification is turned on.
-- This function is responsible for checking ExistentialQuantification as well.
-- (there is no separate checker for that extension)
chkConDeclForExistentials :: CheckNode ConDecl
chkConDeclForExistentials = conditionalAny chkConDeclForExistentials' [GADTs, ExistentialQuantification]

-- If all data constructors are vanilla Haskell 98 data constructors, then only GADTSyntax is needed.
chkGADTsGadtConDecl' :: CheckNode GadtConDecl
chkGADTsGadtConDecl' conDecl = do
  let conNames = conDecl ^. (gadtConNames & annListElems)
  mres <- mapM (runMaybeT . isVanillaDataConNameM) conNames
  if and . catMaybes $ mres
    then addOccurence GADTSyntax conDecl
    else do addOccurence GADTSyntax conDecl
            addRelation (GADTs `lOr` ExistentialQuantification) conDecl

-- Extracts the name from a ConDecl, and checks whether it is a vanilla
-- data constructor.
chkConDeclForExistentials' :: CheckNode ConDecl
chkConDeclForExistentials' conDecl = liftM (fromMaybe conDecl) . runMaybeT $
  case conDecl ^. element of
    UConDecl _ _ n _         -> chkName n
    URecordDecl _ _ n _      -> chkName n
    UInfixConDecl _ _ _ op _ -> chkName (op ^. operatorName)
  where chkName :: HasNameInfo' n => n -> MaybeT ExtMonad ConDecl
        chkName n = do
          isVanilla <- isVanillaDataConNameM n
          if isVanilla
            then return conDecl
            else lift . addRelation (GADTs `lOr` ExistentialQuantification) $ conDecl