{-# LANGUAGE CPP, MultiParamTypeClasses, FunctionalDependencies,
TypeSynonymInstances, FlexibleInstances, LambdaCase #-}
module Language.Haskell.TH.Desugar (
DExp(..), DLetDec(..), DPat(..), DType(..), DKind, DCxt, DPred,
DTyVarBndr(..), DMatch(..), DClause(..), DDec(..),
DDerivClause(..), DDerivStrategy(..), DPatSynDir(..), DPatSynType,
Overlap(..), PatSynArgs(..), NewOrData(..),
DTypeFamilyHead(..), DFamilyResultSig(..), InjectivityAnn(..),
DCon(..), DConFields(..), DDeclaredInfix, DBangType, DVarBangType,
Bang(..), SourceUnpackedness(..), SourceStrictness(..),
DForeign(..),
DPragma(..), DRuleBndr(..), DTySynEqn(..), DInfo(..), DInstanceDec,
Role(..), AnnTarget(..),
Desugar(..),
dsExp, dsDecs, dsType, dsInfo,
dsPatOverExp, dsPatsOverExp, dsPatX,
dsLetDecs, dsTvb, dsCxt,
dsCon, dsForeign, dsPragma, dsRuleBndr,
PatM, dsPred, dsPat, dsDec, dsDataDec, dsDataInstDec,
DerivingClause, dsDerivClause, dsLetDec,
dsMatches, dsBody, dsGuards, dsDoStmts, dsComp, dsClauses,
dsBangType, dsVarBangType,
#if __GLASGOW_HASKELL__ > 710
dsTypeFamilyHead, dsFamilyResultSig,
#endif
#if __GLASGOW_HASKELL__ >= 801
dsPatSynDir,
#endif
dsTypeArg,
module Language.Haskell.TH.Desugar.Sweeten,
expand, expandType,
reifyWithWarning,
withLocalDeclarations, dsReify,
reifyWithLocals_maybe, reifyWithLocals, reifyFixityWithLocals,
lookupValueNameWithLocals, lookupTypeNameWithLocals,
mkDataNameWithLocals, mkTypeNameWithLocals,
reifyNameSpace,
DsMonad(..), DsM,
scExp, scLetDec,
module Language.Haskell.TH.Desugar.Subst,
module Language.Haskell.TH.Desugar.FV,
applyDExp,
dPatToDExp, removeWilds,
getDataD, dataConNameToDataName, dataConNameToCon,
nameOccursIn, allNamesIn, flattenDValD, getRecordSelectors,
mkTypeName, mkDataName, newUniqueName,
mkTupleDExp, mkTupleDPat, maybeDLetE, maybeDCaseE, mkDLamEFromDPats,
tupleDegree_maybe, tupleNameDegree_maybe,
unboxedSumDegree_maybe, unboxedSumNameDegree_maybe,
unboxedTupleDegree_maybe, unboxedTupleNameDegree_maybe,
strictToBang, isTypeKindName, typeKindName,
#if __GLASGOW_HASKELL__ >= 800
bindIP,
#endif
unravel, conExistentialTvbs, mkExtraDKindBinders,
dTyVarBndrToDType, toposortTyVarsOf,
TypeArg(..), applyType, filterTANormals, unfoldType,
DTypeArg(..), applyDType, filterDTANormals, unfoldDType,
extractBoundNamesStmt, extractBoundNamesDec, extractBoundNamesPat
) where
import Language.Haskell.TH.Desugar.AST
import Language.Haskell.TH.Desugar.Core
import Language.Haskell.TH.Desugar.Expand
import Language.Haskell.TH.Desugar.FV
import Language.Haskell.TH.Desugar.Match
import qualified Language.Haskell.TH.Desugar.OSet as OS
import Language.Haskell.TH.Desugar.Reify
import Language.Haskell.TH.Desugar.Subst
import Language.Haskell.TH.Desugar.Sweeten
import Language.Haskell.TH.Desugar.Util
import Language.Haskell.TH.Syntax
import Control.Monad
import qualified Data.Foldable as F
import Data.Function
import Data.List
import qualified Data.Map as M
import qualified Data.Set as S
import Prelude hiding ( exp )
class Desugar th ds | ds -> th where
desugar :: DsMonad q => th -> q ds
sweeten :: ds -> th
instance Desugar Exp DExp where
desugar = dsExp
sweeten = expToTH
instance Desugar Type DType where
desugar = dsType
sweeten = typeToTH
instance Desugar Cxt DCxt where
desugar = dsCxt
sweeten = cxtToTH
instance Desugar TyVarBndr DTyVarBndr where
desugar = dsTvb
sweeten = tvbToTH
instance Desugar [Dec] [DDec] where
desugar = dsDecs
sweeten = decsToTH
instance Desugar TypeArg DTypeArg where
desugar = dsTypeArg
sweeten = typeArgToTH
flattenDValD :: Quasi q => DLetDec -> q [DLetDec]
flattenDValD dec@(DValD (DVarP _) _) = return [dec]
flattenDValD (DValD pat exp) = do
x <- newUniqueName "x"
let top_val_d = DValD (DVarP x) exp
bound_names = F.toList $ extractBoundNamesDPat pat
other_val_ds <- mapM (mk_val_d x) bound_names
return $ top_val_d : other_val_ds
where
mk_val_d x name = do
y <- newUniqueName "y"
let pat' = wildify name y pat
match = DMatch pat' (DVarE y)
cas = DCaseE (DVarE x) [match]
return $ DValD (DVarP name) cas
wildify name y p =
case p of
DLitP lit -> DLitP lit
DVarP n
| n == name -> DVarP y
| otherwise -> DWildP
DConP con ps -> DConP con (map (wildify name y) ps)
DTildeP pa -> DTildeP (wildify name y pa)
DBangP pa -> DBangP (wildify name y pa)
DSigP pa ty -> DSigP (wildify name y pa) ty
DWildP -> DWildP
flattenDValD other_dec = return [other_dec]
getRecordSelectors :: DsMonad q
=> DType
-> [DCon]
-> q [DLetDec]
getRecordSelectors arg_ty cons = merge_let_decs `fmap` concatMapM get_record_sels cons
where
get_record_sels con@(DCon con_tvbs _ con_name con_fields con_ret_ty) =
case con_fields of
DRecC fields -> go fields
DNormalC{} -> return []
where
go fields = do
varName <- qNewName "field"
con_ex_tvbs <- conExistentialTvbs arg_ty con
let con_univ_tvbs = deleteFirstsBy ((==) `on` dtvbName) con_tvbs con_ex_tvbs
con_ex_tvb_set = OS.fromList $ map dtvbName con_ex_tvbs
forall' = DForallT con_univ_tvbs []
num_pats = length fields
return $ concat
[ [ DSigD name (forall' $ DArrowT `DAppT` con_ret_ty `DAppT` field_ty)
, DFunD name [DClause [DConP con_name (mk_field_pats n num_pats varName)]
(DVarE varName)] ]
| ((name, _strict, field_ty), n) <- zip fields [0..]
, OS.null (fvDType field_ty `OS.intersection` con_ex_tvb_set)
]
mk_field_pats :: Int -> Int -> Name -> [DPat]
mk_field_pats 0 total name = DVarP name : (replicate (total-1) DWildP)
mk_field_pats n total name = DWildP : mk_field_pats (n-1) (total-1) name
merge_let_decs :: [DLetDec] -> [DLetDec]
merge_let_decs decs =
let (name_clause_map, decs') = gather_decs M.empty S.empty decs
in augment_clauses name_clause_map decs'
where
gather_decs :: M.Map Name [DClause] -> S.Set Name -> [DLetDec]
-> (M.Map Name [DClause], [DLetDec])
gather_decs name_clause_map _ [] = (name_clause_map, [])
gather_decs name_clause_map type_sig_names (x:xs)
| DFunD n clauses <- x
= let name_clause_map' = M.insertWith (\new old -> old ++ new)
n clauses name_clause_map
in if n `M.member` name_clause_map
then gather_decs name_clause_map' type_sig_names xs
else let (map', decs') = gather_decs name_clause_map'
type_sig_names xs
in (map', x:decs')
| DSigD n _ <- x
= if n `S.member` type_sig_names
then gather_decs name_clause_map type_sig_names xs
else let (map', decs') = gather_decs name_clause_map
(n `S.insert` type_sig_names) xs
in (map', x:decs')
| otherwise =
let (map', decs') = gather_decs name_clause_map type_sig_names xs
in (map', x:decs')
augment_clauses :: M.Map Name [DClause] -> [DLetDec] -> [DLetDec]
augment_clauses _ [] = []
augment_clauses name_clause_map (x:xs)
| DFunD n _ <- x, Just merged_clauses <- n `M.lookup` name_clause_map
= DFunD n merged_clauses:augment_clauses name_clause_map xs
| otherwise = x:augment_clauses name_clause_map xs
mkExtraDKindBinders :: DsMonad q => DKind -> q [DTyVarBndr]
mkExtraDKindBinders = expandType >=> mkExtraDKindBinders'
conExistentialTvbs :: DsMonad q
=> DType
-> DCon
-> q [DTyVarBndr]
conExistentialTvbs data_ty (DCon tvbs _ _ _ ret_ty) = do
data_ty' <- expandType data_ty
ret_ty' <- expandType ret_ty
case matchTy YesIgnore ret_ty' data_ty' of
Nothing -> fail $ showString "Unable to match type "
. showsPrec 11 ret_ty'
. showString " with "
. showsPrec 11 data_ty'
$ ""
Just gadtSubt -> return [ tvb
| tvb <- tvbs
, M.notMember (dtvbName tvb) gadtSubt
]