haskell-tools-backend-ghc-1.1.1.0: Language/Haskell/Tools/BackendGHC/GHCUtils.hs
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
-- | Utility functions defined on the GHC AST representation.
module Language.Haskell.Tools.BackendGHC.GHCUtils where
import Data.Generics.Uniplate.Data ()
import Data.List
import Bag (Bag, bagToList, unionManyBags)
import BasicTypes (SourceText(..))
import ConLike (ConLike(..))
import Data.Maybe (Maybe(..), listToMaybe)
import GHC
import Id (Id, mkVanillaGlobal)
import OccName (OccName)
import Outputable (Outputable(..), showSDocUnsafe)
import PatSyn (patSynSig)
import RdrName (RdrName, rdrNameOcc, nameRdrName)
import SrcLoc
import Type (TyThing(..), mkFunTys)
class (OutputableBndrId name) => GHCName name where
rdrName :: IdP name -> RdrName
getFromNameUsing :: Applicative f => (Name -> Ghc (f Id)) -> Name -> Ghc (f (IdP name))
getBindsAndSigs :: HsValBinds name -> ([LSig name], LHsBinds name)
nameFromId :: Id -> IdP name
fieldOccToId :: RdrName -> XCFieldOcc name -> IdP name
nameIfThereIs :: IdP name -> Maybe Name
instance GHCName GhcPs where
rdrName = id
getFromNameUsing _ n = return $ pure (nameRdrName n)
getBindsAndSigs (ValBinds _ binds sigs) = (sigs, binds)
getBindsAndSigs _ = error "ValBindsOut: ValBindsOut in parsed source"
nameFromId = nameRdrName . getName
fieldOccToId rdr _ = rdr
nameIfThereIs _ = Nothing
occName :: forall n . GHCName n => IdP n -> OccName
occName = rdrNameOcc . rdrName @n
instance GHCName GhcRn where
rdrName = nameRdrName
getFromNameUsing f n = fmap (nameFromId @GhcRn) <$> f n
getBindsAndSigs (XValBindsLR (NValBinds bindGroups sigs)) = (sigs, unionManyBags (map snd bindGroups))
getBindsAndSigs _ = error "getBindsAndSigs: ValBindsIn in renamed source"
nameFromId = getName
fieldOccToId _ name = name
nameIfThereIs name = Just name
getFieldOccName :: forall n . GHCName n => Located (FieldOcc n) -> Located (IdP n)
getFieldOccName (L l (FieldOcc name (L _ rdr))) = L l (fieldOccToId @n rdr name)
getFieldOccName' :: forall n . GHCName n => FieldOcc n -> IdP n
getFieldOccName' (FieldOcc name (L _ rdr)) = fieldOccToId @n rdr name
-- | Loading ids for top-level ghc names
getTopLevelId :: GHC.Name -> Ghc (Maybe GHC.Id)
getTopLevelId name =
lookupName name >>= \case
Just (AnId id) -> return (Just id)
Just (AConLike (RealDataCon dc)) -> return $ Just $ mkVanillaGlobal name (dataConUserType dc)
Just (AConLike (PatSynCon ps)) -> return $ Just $ mkVanillaGlobal name (createPatSynType ps)
Just (ATyCon tc) -> return $ Just $ mkVanillaGlobal name (tyConKind tc)
_ -> return Nothing
where createPatSynType patSyn = case patSynSig patSyn of (_, _, _, _, args, res) -> mkFunTys args res
hsGetNames' :: HsHasName a => a -> [GHC.Name]
hsGetNames' = map fst . hsGetNames Nothing
-- | Get names from the GHC AST
class HsHasName a where
hsGetNames :: Maybe GHC.Name -> a -> [(GHC.Name, Maybe GHC.Name)]
instance HsHasName RdrName where
hsGetNames _ _ = []
instance HsHasName Name where
hsGetNames p n = [(n, p)]
instance HsHasName Id where
hsGetNames p n = [(getName n, p)]
instance HsHasName e => HsHasName [e] where
hsGetNames p es = concatMap (hsGetNames p) es
instance HsHasName e => HsHasName (Located e) where
hsGetNames p (L _ e) = hsGetNames p e
instance HsHasName (IdP (GhcPass n)) => HsHasName (HsLocalBinds (GhcPass n)) where
hsGetNames p (HsValBinds _ bnds) = hsGetNames p bnds
hsGetNames _ _ = []
instance (GHCName n, HsHasName (IdP n)) => HsHasName (HsDecl n) where
hsGetNames p (TyClD _ tycl) = hsGetNames p tycl
hsGetNames p (ValD _ vald) = hsGetNames p vald
hsGetNames p (ForD _ ford) = hsGetNames p ford
hsGetNames p (InstD _ inst) = hsGetNames p inst
hsGetNames _ _ = []
instance (GHCName n, HsHasName (IdP n)) => HsHasName (InstDecl n) where
hsGetNames p (ClsInstD _ clsInst) = hsGetNames p (cid_datafam_insts clsInst)
hsGetNames p (DataFamInstD _ dataFamInst) = hsGetNames p dataFamInst
hsGetNames _ _ = []
instance (GHCName n, HsHasName (IdP n), HsHasName r) => HsHasName (FamEqn n p r) where
hsGetNames p (FamEqn _ id _ _ rhs) = hsGetNames p id ++ hsGetNames p rhs
instance (GHCName n, HsHasName (IdP n)) => HsHasName (DataFamInstDecl n) where
hsGetNames p dfid = hsGetNames p (hsib_body $ dfid_eqn dfid)
instance (GHCName n, HsHasName (IdP n)) => HsHasName (TyClGroup n) where
hsGetNames p (TyClGroup _ tycls _ _) = hsGetNames p tycls
instance (GHCName n, HsHasName (IdP n)) => HsHasName (TyClDecl n) where
hsGetNames p (FamDecl _ fd) = hsGetNames p fd
hsGetNames p (SynDecl {tcdLName = name}) = hsGetNames p name
hsGetNames p (DataDecl {tcdLName = name, tcdDataDefn = datadef})
= let n = hsGetNames p name in n ++ hsGetNames (listToMaybe (map fst n)) datadef
hsGetNames p (ClassDecl {tcdLName = name, tcdSigs = sigs, tcdATs = typeAssocs})
= let n = hsGetNames p name in n ++ hsGetNames (listToMaybe (map fst n)) sigs
++ hsGetNames (listToMaybe (map fst n)) typeAssocs
instance (GHCName n, HsHasName (IdP n)) => HsHasName (FamilyDecl n) where
hsGetNames p (FamilyDecl { fdLName = name }) = hsGetNames p name
instance (GHCName n, HsHasName (IdP n)) => HsHasName (HsDataDefn n) where
hsGetNames p (HsDataDefn {dd_cons = ctors}) = hsGetNames p ctors
instance (GHCName n, HsHasName (IdP n)) => HsHasName (ConDecl n) where
hsGetNames p (ConDeclGADT {con_names = names, con_res_ty = (L _ (HsFunTy _ (L _ (HsRecTy _ flds)) _))})
= hsGetNames p names ++ hsGetNames p flds
hsGetNames p (ConDeclGADT {con_names = names, con_res_ty = (L _ (HsRecTy _ flds))})
= hsGetNames p names ++ hsGetNames p flds
hsGetNames p (ConDeclGADT {con_names = names}) = hsGetNames p names
hsGetNames p (ConDeclH98 {con_name = name, con_args = details})
= hsGetNames p name ++ hsGetNames p details
instance (GHCName n, HsHasName (IdP n)) => HsHasName (HsConDeclDetails n) where
hsGetNames p (RecCon rec) = hsGetNames p rec
hsGetNames _ _ = []
instance (GHCName n, HsHasName (IdP n)) => HsHasName (ConDeclField n) where
hsGetNames p (ConDeclField _ name _ _) = hsGetNames p name
instance forall n . (GHCName n, HsHasName (IdP n)) => HsHasName (FieldOcc n) where
hsGetNames p fl = case nameIfThereIs @n (getFieldOccName' fl) of Just n -> [(n, p)]
_ -> []
instance (GHCName n, HsHasName (IdP n)) => HsHasName (Sig n) where
hsGetNames p (TypeSig _ n _) = hsGetNames p n
hsGetNames p (ClassOpSig _ _ n _) = hsGetNames p n
hsGetNames p (PatSynSig _ n _) = hsGetNames p n
hsGetNames _ _ = []
instance HsHasName (IdP n) => HsHasName (ForeignDecl n) where
hsGetNames p (ForeignImport _ n _ _) = hsGetNames p n
hsGetNames _ _ = []
instance forall n . HsHasName (IdP (GhcPass n)) => HsHasName (HsValBinds (GhcPass n)) where
hsGetNames p (ValBinds _ bnds _) = hsGetNames p bnds
hsGetNames p (XValBindsLR (NValBinds bnds _ :: NHsValBindsLR (GhcPass n))) = hsGetNames p $ map snd bnds
instance HsHasName n => HsHasName (Bag n) where
hsGetNames p = hsGetNames p . bagToList
instance HsHasName (IdP n) => HsHasName (HsBind n) where
hsGetNames p (FunBind {fun_id = lname}) = hsGetNames p lname
hsGetNames p (PatBind {pat_lhs = pat}) = hsGetNames p pat
hsGetNames p (VarBind {var_id = id}) = hsGetNames p id
hsGetNames p (PatSynBind _ (PSB {psb_id = id})) = hsGetNames p id
hsGetNames _ _ = error "hsGetNames: called on compiler-generated binding"
instance HsHasName (IdP n) => HsHasName (ParStmtBlock l n) where
hsGetNames p (ParStmtBlock _ _ binds _) = hsGetNames p binds
--instance HsHasName n => HsHasName (LHsTyVarBndrs n) where
-- hsGetNames (HsQTvs kvs tvs) = hsGetNames kvs ++ hsGetNames tvs
instance HsHasName (IdP n) => HsHasName (HsTyVarBndr n) where
hsGetNames p (UserTyVar _ n) = hsGetNames p n
hsGetNames p (KindedTyVar _ n _) = hsGetNames p n
hsGetNames _ _ = []
instance HsHasName (IdP n) => HsHasName (Match n b) where
hsGetNames p (Match _ _ pats _) = concatMap (hsGetNames p) pats
instance HsHasName (IdP (GhcPass n)) => HsHasName (StmtLR (GhcPass n) (GhcPass n) b) where
hsGetNames p (LetStmt _ binds) = hsGetNames p binds
hsGetNames p (BindStmt _ pat _ _ _) = hsGetNames p pat
hsGetNames p (RecStmt {recS_rec_ids = ids}) = hsGetNames p ids
hsGetNames _ _ = []
instance HsHasName (IdP n) => HsHasName (Pat n) where
hsGetNames x (VarPat _ id) = hsGetNames x id
hsGetNames x (LazyPat _ p) = hsGetNames x p
hsGetNames x (AsPat _ lname p) = hsGetNames x lname ++ hsGetNames x p
hsGetNames x (ParPat _ p) = hsGetNames x p
hsGetNames x (BangPat _ p) = hsGetNames x p
hsGetNames x (ListPat _ pats) = concatMap (hsGetNames x) pats
hsGetNames x (TuplePat _ pats _) = concatMap (hsGetNames x) pats
hsGetNames x (ConPatIn _ details) = concatMap (hsGetNames x) (hsConPatArgs details)
hsGetNames x (ConPatOut {pat_args = details}) = concatMap (hsGetNames x) (hsConPatArgs details)
hsGetNames x (ViewPat _ _ p) = hsGetNames x p
hsGetNames x (NPlusKPat _ lname _ _ _ _) = hsGetNames x lname
hsGetNames x (SigPat _ p) = hsGetNames x p
hsGetNames _ _ = []
instance (GHCName (GhcPass n), HsHasName (IdP (GhcPass n))) => HsHasName (HsGroup (GhcPass n)) where
hsGetNames p g@(HsGroup _ vals _ clds _ _ _ foreigns _ _ _ _)
= hsGetNames p vals ++ hsGetNames p clds ++ hsGetNames p (hsGroupInstDecls g) ++ hsGetNames p foreigns
-- instance (GHCName n, HsHasName (IdP n)) => HsHasName (DefaultDecl n) where
-- hsGetNames p (DefaultDecl _ ts) = hsGetNames p ts
-- hsGetNames _ _ = []
-- | Get the original form of a name
rdrNameStr :: RdrName -> String
rdrNameStr name = showSDocUnsafe $ ppr name
class FromGHCName n where
fromGHCName :: GHC.Name -> n
instance FromGHCName RdrName where
fromGHCName = rdrName @GhcRn
instance FromGHCName GHC.Name where
fromGHCName = id
{-
-- | Tries to simplify the type that has HsAppsTy before renaming. Does not always provide the correct form.
-- Treats each operator as if they are of equivalent precedence and always left-associative.
cleanHsType :: forall n . (OutputableBndrId n {-, SourceTextX n -}) => HsType n -> HsType n
-- for some reason * is considered infix
cleanHsType (HsAppsTy apps) = unLoc $ guessType apps
where guessType :: OutputableBndrId n => [LHsAppType n] -> LHsType n
guessType (L l (HsAppInfix n) : rest) -- must be a prefix actually
= guessType' (L l (HsTyVar NotPromoted n)) rest
guessType (L _ (HsAppPrefix t) : rest) = guessType' t rest
guessType [] = error $ "guessType: empty" ++ showSDocUnsafe (ppr apps)
guessType' :: LHsType n -> [LHsAppType n] -> LHsType n
guessType' fun (L _ (HsAppPrefix t) : rest) = guessType' (hsAppTy fun t) rest
guessType' fun (L l (HsAppInfix n) : rest)
-- TODO: find a better check
| showSDocUnsafe (ppr n) == "*" = guessType' (hsAppTy fun (L l (HsTyVar NotPromoted n))) rest
guessType' left (L _ (HsAppInfix n) : right) = hsOpTy left n (guessType right)
guessType' t [] = t
hsAppTy :: LHsType n -> LHsType n -> LHsType n
hsAppTy t1 t2 = L (getLoc t1 `combineSrcSpans` getLoc t2) $ HsAppTy t1 t2
hsOpTy :: LHsType n -> Located (IdP n) -> LHsType n -> LHsType n
hsOpTy t1 n t2 = L (getLoc t1 `combineSrcSpans` getLoc t2) $ HsOpTy t1 n t2
cleanHsType t = t
-}
mergeFixityDefs :: [Located (FixitySig n)] -> [Located (FixitySig n)]
mergeFixityDefs (s@(L l _) : rest)
= let (same, different) = partition ((== l) . getLoc) rest
in foldl mergeWith s (map unLoc same) : mergeFixityDefs different
where mergeWith (L l (FixitySig x names fixity)) (FixitySig _ otherNames _) = L l (FixitySig x (names ++ otherNames) fixity)
mergeFixityDefs [] = []
getGroupRange :: HsGroup (GhcPass n) -> SrcSpan
getGroupRange (HsGroup {..})
= foldr combineSrcSpans noSrcSpan locs
where locs = [getHsValRange hs_valds] ++ map getLoc hs_splcds ++ map getLoc (concatMap group_tyclds hs_tyclds)
++ map getLoc (concatMap group_roles hs_tyclds)
++ map getLoc hs_derivds ++ map getLoc hs_fixds ++ map getLoc hs_defds
++ map getLoc hs_fords ++ map getLoc hs_warnds ++ map getLoc hs_annds ++ map getLoc hs_ruleds
++ map getLoc hs_docs
getHsValRange :: HsValBinds (GhcPass n) -> SrcSpan
getHsValRange (ValBinds _ vals sig) = foldr combineSrcSpans noSrcSpan $ map getLoc (bagToList vals) ++ map getLoc sig
getHsValRange ((XValBindsLR (NValBinds vals sig))) = foldr combineSrcSpans noSrcSpan $ concatMap (map getLoc . bagToList . snd) vals ++ map getLoc sig
fromSrcText :: SourceText -> String
fromSrcText (SourceText s) = s
fromSrcText NoSourceText = ""