{-# LANGUAGE CPP, GeneralizedNewtypeDeriving, ScopedTypeVariables #-}
module Language.Haskell.TH.Desugar.Reify (
reifyWithLocals_maybe, reifyWithLocals, reifyWithWarning, reifyInDecs,
qReifyFixity, reifyFixity, reifyFixityWithLocals, reifyFixityInDecs,
qReifyType, reifyType,
reifyTypeWithLocals_maybe, reifyTypeWithLocals, reifyTypeInDecs,
getDataD, dataConNameToCon, dataConNameToDataName,
lookupValueNameWithLocals, lookupTypeNameWithLocals,
mkDataNameWithLocals, mkTypeNameWithLocals,
reifyNameSpace,
DsMonad(..), DsM, withLocalDeclarations
) where
import Control.Applicative
import qualified Control.Monad.Fail as Fail
import Control.Monad.Reader
import Control.Monad.State
import Control.Monad.Writer
import Control.Monad.RWS
import Control.Monad.Trans.Instances ()
import qualified Data.Foldable as F
#if __GLASGOW_HASKELL__ < 710
import Data.Foldable (foldMap)
#endif
import Data.Function (on)
import Data.List
import qualified Data.Map as Map
import Data.Map (Map)
import Data.Maybe
import qualified Data.Set as Set
import Data.Set (Set)
import Language.Haskell.TH.Datatype
import Language.Haskell.TH.Instances ()
import Language.Haskell.TH.Syntax hiding ( lift )
import Language.Haskell.TH.Desugar.Util
reifyWithLocals_maybe :: DsMonad q => Name -> q (Maybe Info)
reifyWithLocals_maybe name = qRecover
(return . reifyInDecs name =<< localDeclarations)
(Just `fmap` qReify name)
reifyWithLocals :: DsMonad q => Name -> q Info
reifyWithLocals name = do
m_info <- reifyWithLocals_maybe name
case m_info of
Nothing -> reifyFail name
Just i -> return i
reifyWithWarning :: (Quasi q, Fail.MonadFail q) => Name -> q Info
reifyWithWarning name = qRecover (reifyFail name) (qReify name)
reifyFail :: Fail.MonadFail m => Name -> m a
reifyFail name =
Fail.fail $ "Looking up " ++ (show name) ++ " in the list of available " ++
"declarations failed.\nThis lookup fails if the declaration " ++
"referenced was made in the same Template\nHaskell splice as the use " ++
"of the declaration. If this is the case, put\nthe reference to " ++
"the declaration in a new splice."
getDataD :: DsMonad q
=> String
-> Name
-> q ([TyVarBndr], [Con])
getDataD err name = do
info <- reifyWithLocals name
dec <- case info of
TyConI dec -> return dec
_ -> badDeclaration
case dec of
#if __GLASGOW_HASKELL__ > 710
DataD _cxt _name tvbs mk cons _derivings -> go tvbs mk cons
NewtypeD _cxt _name tvbs mk con _derivings -> go tvbs mk [con]
#else
DataD _cxt _name tvbs cons _derivings -> go tvbs Nothing cons
NewtypeD _cxt _name tvbs con _derivings -> go tvbs Nothing [con]
#endif
_ -> badDeclaration
where
go tvbs mk cons = do
let k = fromMaybe (ConT typeKindName) mk
extra_tvbs <- mkExtraKindBinders k
let all_tvbs = tvbs ++ extra_tvbs
return (all_tvbs, cons)
badDeclaration =
fail $ "The name (" ++ (show name) ++ ") refers to something " ++
"other than a datatype. " ++ err
mkExtraKindBinders :: forall q. Quasi q => Kind -> q [TyVarBndr]
mkExtraKindBinders k = do
k' <- runQ $ resolveTypeSynonyms k
let (fun_args, _) = unravelType k'
vis_fun_args = filterVisFunArgs fun_args
mapM mk_tvb vis_fun_args
where
mk_tvb :: VisFunArg -> q TyVarBndr
mk_tvb (VisFADep tvb) = return tvb
mk_tvb (VisFAAnon ki) = KindedTV <$> qNewName "a" <*> return ki
dataConNameToDataName :: DsMonad q => Name -> q Name
dataConNameToDataName con_name = do
info <- reifyWithLocals con_name
case info of
#if __GLASGOW_HASKELL__ > 710
DataConI _name _type parent_name -> return parent_name
#else
DataConI _name _type parent_name _fixity -> return parent_name
#endif
_ -> fail $ "The name " ++ show con_name ++ " does not appear to be " ++
"a data constructor."
dataConNameToCon :: DsMonad q => Name -> q Con
dataConNameToCon con_name = do
type_name <- dataConNameToDataName con_name
(_, cons) <- getDataD "This seems to be an error in GHC." type_name
let m_con = find (any (con_name ==) . get_con_name) cons
case m_con of
Just con -> return con
Nothing -> impossible "Datatype does not contain one of its own constructors."
where
get_con_name (NormalC name _) = [name]
get_con_name (RecC name _) = [name]
get_con_name (InfixC _ name _) = [name]
get_con_name (ForallC _ _ con) = get_con_name con
#if __GLASGOW_HASKELL__ > 710
get_con_name (GadtC names _ _) = names
get_con_name (RecGadtC names _ _) = names
#endif
class (Quasi m, Fail.MonadFail m) => DsMonad m where
localDeclarations :: m [Dec]
instance DsMonad Q where
localDeclarations = return []
instance DsMonad IO where
localDeclarations = return []
newtype DsM q a = DsM (ReaderT [Dec] q a)
deriving ( Functor, Applicative, Monad, MonadTrans, Quasi, Fail.MonadFail
#if __GLASGOW_HASKELL__ >= 803
, MonadIO
#endif
)
instance (Quasi q, Fail.MonadFail q) => DsMonad (DsM q) where
localDeclarations = DsM ask
instance DsMonad m => DsMonad (ReaderT r m) where
localDeclarations = lift localDeclarations
instance DsMonad m => DsMonad (StateT s m) where
localDeclarations = lift localDeclarations
instance (DsMonad m, Monoid w) => DsMonad (WriterT w m) where
localDeclarations = lift localDeclarations
instance (DsMonad m, Monoid w) => DsMonad (RWST r w s m) where
localDeclarations = lift localDeclarations
withLocalDeclarations :: DsMonad q => [Dec] -> DsM q a -> q a
withLocalDeclarations new_decs (DsM x) = do
orig_decs <- localDeclarations
runReaderT x (orig_decs ++ new_decs)
reifyInDecs :: Name -> [Dec] -> Maybe Info
reifyInDecs n decs = snd `fmap` firstMatch (reifyInDec n decs) decs
reifyFixityInDecs :: Name -> [Dec] -> Maybe Fixity
reifyFixityInDecs n = firstMatch match_fixity
where
match_fixity (InfixD fixity n') | n `nameMatches` n'
= Just fixity
match_fixity (ClassD _ _ _ _ sub_decs) = firstMatch match_fixity sub_decs
match_fixity _ = Nothing
type Named a = (Name, a)
reifyInDec :: Name -> [Dec] -> Dec -> Maybe (Named Info)
reifyInDec n decs (FunD n' _) | n `nameMatches` n' = Just (n', mkVarI n decs)
reifyInDec n decs (ValD pat _ _)
| Just n' <- find (nameMatches n) (F.toList (extractBoundNamesPat pat)) = Just (n', mkVarI n decs)
#if __GLASGOW_HASKELL__ > 710
reifyInDec n _ dec@(DataD _ n' _ _ _ _) | n `nameMatches` n' = Just (n', TyConI dec)
reifyInDec n _ dec@(NewtypeD _ n' _ _ _ _) | n `nameMatches` n' = Just (n', TyConI dec)
#else
reifyInDec n _ dec@(DataD _ n' _ _ _) | n `nameMatches` n' = Just (n', TyConI dec)
reifyInDec n _ dec@(NewtypeD _ n' _ _ _) | n `nameMatches` n' = Just (n', TyConI dec)
#endif
reifyInDec n _ dec@(TySynD n' _ _) | n `nameMatches` n' = Just (n', TyConI dec)
reifyInDec n decs dec@(ClassD _ n' _ _ _) | n `nameMatches` n'
= Just (n', ClassI (quantifyClassDecMethods dec) (findInstances n decs))
reifyInDec n decs (ForeignD (ImportF _ _ _ n' ty)) | n `nameMatches` n'
= Just (n', mkVarITy n decs ty)
reifyInDec n decs (ForeignD (ExportF _ _ n' ty)) | n `nameMatches` n'
= Just (n', mkVarITy n decs ty)
#if __GLASGOW_HASKELL__ > 710
reifyInDec n decs dec@(OpenTypeFamilyD (TypeFamilyHead n' _ _ _)) | n `nameMatches` n'
= Just (n', FamilyI dec (findInstances n decs))
reifyInDec n decs dec@(DataFamilyD n' _ _) | n `nameMatches` n'
= Just (n', FamilyI dec (findInstances n decs))
reifyInDec n _ dec@(ClosedTypeFamilyD (TypeFamilyHead n' _ _ _) _) | n `nameMatches` n'
= Just (n', FamilyI dec [])
#else
reifyInDec n decs dec@(FamilyD _ n' _ _) | n `nameMatches` n'
= Just (n', FamilyI dec (findInstances n decs))
reifyInDec n _ dec@(ClosedTypeFamilyD n' _ _ _) | n `nameMatches` n'
= Just (n', FamilyI dec [])
#endif
#if __GLASGOW_HASKELL__ >= 801
reifyInDec n decs (PatSynD n' _ _ _) | n `nameMatches` n'
= Just (n', mkPatSynI n decs)
#endif
#if __GLASGOW_HASKELL__ > 710
reifyInDec n decs (DataD _ ty_name tvbs _mk cons _)
| Just info <- maybeReifyCon n decs ty_name (map tvbToTANormalWithSig tvbs) cons
= Just info
reifyInDec n decs (NewtypeD _ ty_name tvbs _mk con _)
| Just info <- maybeReifyCon n decs ty_name (map tvbToTANormalWithSig tvbs) [con]
= Just info
#else
reifyInDec n decs (DataD _ ty_name tvbs cons _)
| Just info <- maybeReifyCon n decs ty_name (map tvbToTANormalWithSig tvbs) cons
= Just info
reifyInDec n decs (NewtypeD _ ty_name tvbs con _)
| Just info <- maybeReifyCon n decs ty_name (map tvbToTANormalWithSig tvbs) [con]
= Just info
#endif
#if __GLASGOW_HASKELL__ > 710
reifyInDec n _decs (ClassD _ ty_name tvbs _ sub_decs)
| Just (n', ty) <- findType n sub_decs
= Just (n', ClassOpI n (quantifyClassMethodType ty_name tvbs True ty) ty_name)
#else
reifyInDec n decs (ClassD _ ty_name tvbs _ sub_decs)
| Just (n', ty) <- findType n sub_decs
= Just (n', ClassOpI n (quantifyClassMethodType ty_name tvbs True ty)
ty_name (fromMaybe defaultFixity $
reifyFixityInDecs n $ sub_decs ++ decs))
#endif
reifyInDec n decs (ClassD _ _ _ _ sub_decs)
| Just info <- firstMatch (reifyInDec n decs) sub_decs
= Just info
#if __GLASGOW_HASKELL__ >= 711
reifyInDec n decs (InstanceD _ _ _ sub_decs)
#else
reifyInDec n decs (InstanceD _ _ sub_decs)
#endif
| Just info <- firstMatch reify_in_instance sub_decs
= Just info
where
reify_in_instance dec@(DataInstD {}) = reifyInDec n (sub_decs ++ decs) dec
reify_in_instance dec@(NewtypeInstD {}) = reifyInDec n (sub_decs ++ decs) dec
reify_in_instance _ = Nothing
#if __GLASGOW_HASKELL__ >= 807
reifyInDec n decs (DataInstD _ _ lhs _ cons _)
| (ConT ty_name, tys) <- unfoldType lhs
, Just info <- maybeReifyCon n decs ty_name tys cons
= Just info
reifyInDec n decs (NewtypeInstD _ _ lhs _ con _)
| (ConT ty_name, tys) <- unfoldType lhs
, Just info <- maybeReifyCon n decs ty_name tys [con]
= Just info
#elif __GLASGOW_HASKELL__ > 710
reifyInDec n decs (DataInstD _ ty_name tys _ cons _)
| Just info <- maybeReifyCon n decs ty_name (map TANormal tys) cons
= Just info
reifyInDec n decs (NewtypeInstD _ ty_name tys _ con _)
| Just info <- maybeReifyCon n decs ty_name (map TANormal tys) [con]
= Just info
#else
reifyInDec n decs (DataInstD _ ty_name tys cons _)
| Just info <- maybeReifyCon n decs ty_name (map TANormal tys) cons
= Just info
reifyInDec n decs (NewtypeInstD _ ty_name tys con _)
| Just info <- maybeReifyCon n decs ty_name (map TANormal tys) [con]
= Just info
#endif
reifyInDec _ _ _ = Nothing
maybeReifyCon :: Name -> [Dec] -> Name -> [TypeArg] -> [Con] -> Maybe (Named Info)
maybeReifyCon n _decs ty_name ty_args cons
| Just (n', con) <- findCon n cons
, let full_con_ty = unSigType $ con_to_type h98_tvbs h98_res_ty con
= Just ( n', DataConI n full_con_ty ty_name
#if __GLASGOW_HASKELL__ < 800
fixity
#endif
)
| Just (n', rec_sel_info) <- findRecSelector n cons
, let (tvbs, sel_ty, con_res_ty) = extract_rec_sel_info rec_sel_info
full_sel_ty = unSigType $ maybeForallT tvbs [] $ mkArrows [con_res_ty] sel_ty
= Just ( n', VarI n full_sel_ty Nothing
#if __GLASGOW_HASKELL__ < 800
fixity
#endif
)
where
extract_rec_sel_info :: RecSelInfo -> ([TyVarBndr], Type, Type)
extract_rec_sel_info rec_sel_info =
case rec_sel_info of
RecSelH98 sel_ty -> (h98_tvbs, sel_ty, h98_res_ty)
RecSelGADT sel_ty con_res_ty ->
( freeVariablesWellScoped [con_res_ty, sel_ty]
, sel_ty, con_res_ty)
h98_tvbs = freeVariablesWellScoped $ map probablyWrongUnTypeArg ty_args
h98_res_ty = applyType (ConT ty_name) ty_args
#if __GLASGOW_HASKELL__ < 800
fixity = fromMaybe defaultFixity $ reifyFixityInDecs n _decs
#endif
maybeReifyCon _ _ _ _ _ = Nothing
con_to_type :: [TyVarBndr]
-> Type
-> Con -> Type
con_to_type h98_tvbs h98_result_ty con =
case go con of
(is_gadt, ty) | is_gadt -> ty
| otherwise -> maybeForallT h98_tvbs [] ty
where
go :: Con -> (Bool, Type)
go (NormalC _ stys) = (False, mkArrows (map snd stys) h98_result_ty)
go (RecC _ vstys) = (False, mkArrows (map thdOf3 vstys) h98_result_ty)
go (InfixC t1 _ t2) = (False, mkArrows (map snd [t1, t2]) h98_result_ty)
go (ForallC bndrs cxt c) = liftSnd (ForallT bndrs cxt) (go c)
#if __GLASGOW_HASKELL__ > 710
go (GadtC _ stys rty) = (True, mkArrows (map snd stys) rty)
go (RecGadtC _ vstys rty) = (True, mkArrows (map thdOf3 vstys) rty)
#endif
mkVarI :: Name -> [Dec] -> Info
mkVarI n decs = mkVarITy n decs (maybe (no_type n) snd $ findType n decs)
mkVarITy :: Name -> [Dec] -> Type -> Info
#if __GLASGOW_HASKELL__ > 710
mkVarITy n _decs ty = VarI n ty Nothing
#else
mkVarITy n decs ty = VarI n ty Nothing (fromMaybe defaultFixity $
reifyFixityInDecs n decs)
#endif
findType :: Name -> [Dec] -> Maybe (Named Type)
findType n = firstMatch match_type
where
match_type (SigD n' ty) | n `nameMatches` n' = Just (n', ty)
match_type _ = Nothing
#if __GLASGOW_HASKELL__ >= 801
mkPatSynI :: Name -> [Dec] -> Info
mkPatSynI n decs = PatSynI n (fromMaybe (no_type n) $ findPatSynType n decs)
findPatSynType :: Name -> [Dec] -> Maybe PatSynType
findPatSynType n = firstMatch match_pat_syn_type
where
match_pat_syn_type (PatSynSigD n' psty) | n `nameMatches` n' = Just psty
match_pat_syn_type _ = Nothing
#endif
no_type :: Name -> Type
no_type n = error $ "No type information found in local declaration for "
++ show n
findInstances :: Name -> [Dec] -> [Dec]
findInstances n = map stripInstanceDec . concatMap match_instance
where
#if __GLASGOW_HASKELL__ >= 711
match_instance d@(InstanceD _ _ ty _)
#else
match_instance d@(InstanceD _ ty _)
#endif
| ConT n' <- ty_head ty
, n `nameMatches` n' = [d]
#if __GLASGOW_HASKELL__ >= 807
match_instance (DataInstD ctxt _ lhs mk cons derivs)
| ConT n' <- ty_head lhs
, n `nameMatches` n' = [d]
where
mtvbs = rejig_data_inst_tvbs ctxt lhs mk
d = DataInstD ctxt mtvbs lhs mk cons derivs
match_instance (NewtypeInstD ctxt _ lhs mk con derivs)
| ConT n' <- ty_head lhs
, n `nameMatches` n' = [d]
where
mtvbs = rejig_data_inst_tvbs ctxt lhs mk
d = NewtypeInstD ctxt mtvbs lhs mk con derivs
#elif __GLASGOW_HASKELL__ > 710
match_instance d@(DataInstD _ n' _ _ _ _) | n `nameMatches` n' = [d]
match_instance d@(NewtypeInstD _ n' _ _ _ _) | n `nameMatches` n' = [d]
#else
match_instance d@(DataInstD _ n' _ _ _) | n `nameMatches` n' = [d]
match_instance d@(NewtypeInstD _ n' _ _ _) | n `nameMatches` n' = [d]
#endif
#if __GLASGOW_HASKELL__ >= 807
match_instance (TySynInstD (TySynEqn _ lhs rhs))
| ConT n' <- ty_head lhs
, n `nameMatches` n' = [d]
where
mtvbs = rejig_tvbs [lhs, rhs]
d = TySynInstD (TySynEqn mtvbs lhs rhs)
#else
match_instance d@(TySynInstD n' _) | n `nameMatches` n' = [d]
#endif
#if __GLASGOW_HASKELL__ >= 711
match_instance (InstanceD _ _ _ decs)
#else
match_instance (InstanceD _ _ decs)
#endif
= concatMap match_instance decs
match_instance _ = []
#if __GLASGOW_HASKELL__ >= 807
rejig_tvbs :: [Type] -> Maybe [TyVarBndr]
rejig_tvbs ts =
let tvbs = freeVariablesWellScoped ts
in if null tvbs
then Nothing
else Just tvbs
rejig_data_inst_tvbs :: Cxt -> Type -> Maybe Kind -> Maybe [TyVarBndr]
rejig_data_inst_tvbs cxt lhs mk =
rejig_tvbs $ cxt ++ [lhs] ++ maybeToList mk
#endif
ty_head = fst . unfoldType
quantifyClassDecMethods :: Dec -> Dec
quantifyClassDecMethods (ClassD cxt cls_name cls_tvbs fds sub_decs)
= ClassD cxt cls_name cls_tvbs fds sub_decs'
where
sub_decs' = mapMaybe go sub_decs
go (SigD n ty) =
Just $ SigD n
$ quantifyClassMethodType cls_name cls_tvbs prepend_cls ty
go d@(TySynInstD {}) = Just d
#if __GLASGOW_HASKELL__ > 710
go d@(OpenTypeFamilyD {}) = Just d
go d@(DataFamilyD {}) = Just d
#endif
go _ = Nothing
prepend_cls :: Bool
#if __GLASGOW_HASKELL__ >= 807
prepend_cls = False
#else
prepend_cls = True
#endif
quantifyClassDecMethods dec = dec
quantifyClassMethodType
:: Name
-> [TyVarBndr]
-> Bool
-> Type
-> Type
quantifyClassMethodType cls_name cls_tvbs prepend meth_ty =
add_cls_cxt quantified_meth_ty
where
add_cls_cxt :: Type -> Type
add_cls_cxt
| prepend = ForallT all_cls_tvbs cls_cxt
| otherwise = id
cls_cxt :: Cxt
#if __GLASGOW_HASKELL__ < 709
cls_cxt = [ClassP cls_name (map tvbToType cls_tvbs)]
#else
cls_cxt = [foldl AppT (ConT cls_name) (map tvbToType cls_tvbs)]
#endif
quantified_meth_ty :: Type
quantified_meth_ty
| null meth_tvbs
= meth_ty
| ForallT meth_tvbs' meth_ctxt meth_tau <- meth_ty
= ForallT (meth_tvbs ++ meth_tvbs') meth_ctxt meth_tau
| otherwise
= ForallT meth_tvbs [] meth_ty
meth_tvbs :: [TyVarBndr]
meth_tvbs = deleteFirstsBy ((==) `on` tvName)
(freeVariablesWellScoped [meth_ty]) all_cls_tvbs
all_cls_tvbs :: [TyVarBndr]
all_cls_tvbs = freeVariablesWellScoped $ map tvbToTypeWithSig cls_tvbs
stripInstanceDec :: Dec -> Dec
#if __GLASGOW_HASKELL__ >= 711
stripInstanceDec (InstanceD over cxt ty _) = InstanceD over cxt ty []
#else
stripInstanceDec (InstanceD cxt ty _) = InstanceD cxt ty []
#endif
stripInstanceDec dec = dec
mkArrows :: [Type] -> Type -> Type
mkArrows [] res_ty = res_ty
mkArrows (t:ts) res_ty = AppT (AppT ArrowT t) $ mkArrows ts res_ty
maybeForallT :: [TyVarBndr] -> Cxt -> Type -> Type
maybeForallT tvbs cxt ty
| null tvbs && null cxt = ty
| ForallT tvbs2 cxt2 ty2 <- ty = ForallT (tvbs ++ tvbs2) (cxt ++ cxt2) ty2
| otherwise = ForallT tvbs cxt ty
findCon :: Name -> [Con] -> Maybe (Named Con)
findCon n = firstMatch match_con
where
match_con :: Con -> Maybe (Named Con)
match_con con =
case con of
NormalC n' _ | n `nameMatches` n' -> Just (n', con)
RecC n' _ | n `nameMatches` n' -> Just (n', con)
InfixC _ n' _ | n `nameMatches` n' -> Just (n', con)
ForallC _ _ c -> case match_con c of
Just (n', _) -> Just (n', con)
Nothing -> Nothing
#if __GLASGOW_HASKELL__ > 710
GadtC nms _ _ -> gadt_case con nms
RecGadtC nms _ _ -> gadt_case con nms
#endif
_ -> Nothing
#if __GLASGOW_HASKELL__ > 710
gadt_case :: Con -> [Name] -> Maybe (Named Con)
gadt_case con nms = case find (n `nameMatches`) nms of
Just n' -> Just (n', con)
Nothing -> Nothing
#endif
data RecSelInfo
= RecSelH98 Type
| RecSelGADT Type
Type
findRecSelector :: Name -> [Con] -> Maybe (Named RecSelInfo)
findRecSelector n = firstMatch match_con
where
match_con :: Con -> Maybe (Named RecSelInfo)
match_con (RecC _ vstys) = fmap (liftSnd RecSelH98) $
firstMatch match_rec_sel vstys
#if __GLASGOW_HASKELL__ >= 800
match_con (RecGadtC _ vstys ret_ty) = fmap (liftSnd (`RecSelGADT` ret_ty)) $
firstMatch match_rec_sel vstys
#endif
match_con (ForallC _ _ c) = match_con c
match_con _ = Nothing
match_rec_sel (n', _, sel_ty)
| n `nameMatches` n' = Just (n', sel_ty)
match_rec_sel _ = Nothing
#if __GLASGOW_HASKELL__ < 711
qReifyFixity :: Quasi m => Name -> m (Maybe Fixity)
qReifyFixity name = do
info <- qReify name
return $ case info of
ClassOpI _ _ _ fixity -> Just fixity
DataConI _ _ _ fixity -> Just fixity
VarI _ _ _ fixity -> Just fixity
_ -> Nothing
reifyFixity :: Name -> Q (Maybe Fixity)
reifyFixity = qReifyFixity
#endif
reifyFixityWithLocals :: DsMonad q => Name -> q (Maybe Fixity)
reifyFixityWithLocals name = qRecover
(return . reifyFixityInDecs name =<< localDeclarations)
(qReifyFixity name)
#if __GLASGOW_HASKELL__ < 809
qReifyType :: forall m. Quasi m => Name -> m Type
qReifyType name = do
info <- qReify name
case infoType info <|> info_kind info of
Just t -> return t
Nothing -> fail $ "Could not reify the full type of " ++ nameBase name
where
info_kind :: Info -> Maybe Kind
info_kind info = do
dec <- case info of
ClassI d _ -> Just d
TyConI d -> Just d
FamilyI d _ -> Just d
_ -> Nothing
match_cusk name dec
reifyType :: Name -> Q Type
reifyType = qReifyType
#endif
reifyTypeWithLocals :: DsMonad q => Name -> q Type
reifyTypeWithLocals name = do
m_info <- reifyTypeWithLocals_maybe name
case m_info of
Nothing -> reifyFail name
Just i -> return i
reifyTypeWithLocals_maybe :: DsMonad q => Name -> q (Maybe Type)
reifyTypeWithLocals_maybe name = do
#if __GLASGOW_HASKELL__ >= 809
cusks <- qIsExtEnabled CUSKs
#else
let cusks = True
#endif
qRecover (return . reifyTypeInDecs cusks name =<< localDeclarations)
(Just `fmap` qReifyType name)
reifyTypeInDecs :: Bool -> Name -> [Dec] -> Maybe Type
reifyTypeInDecs cusks name decs =
(reifyInDecs name decs >>= infoType) <|> findKind cusks name decs
infoType :: Info -> Maybe Type
infoType info =
case info of
ClassOpI _ t _
#if __GLASGOW_HASKELL__ < 800
_
#endif
-> Just t
DataConI _ t _
#if __GLASGOW_HASKELL__ < 800
_
#endif
-> Just t
VarI _ t _
#if __GLASGOW_HASKELL__ < 800
_
#endif
-> Just t
TyVarI _ t -> Just t
#if __GLASGOW_HASKELL__ >= 802
PatSynI _ t -> Just t
#endif
_ -> Nothing
findKind :: Bool
-> Name -> [Dec] -> Maybe Kind
findKind cusks name decls =
firstMatch (match_kind_sig name decls) decls
<|> whenAlt cusks (firstMatch (match_cusk name) decls)
match_kind_sig :: Name -> [Dec] -> Dec -> Maybe Kind
match_kind_sig n decs (ClassD _ n' tvbs _ sub_decs)
| Just ki <- firstMatch (find_kind_sig n') decs
, let (arg_kis, _res_ki) = unravelType ki
mb_vis_arg_kis = map vis_arg_kind_maybe $ filterVisFunArgs arg_kis
cls_tvb_kind_map =
Map.fromList [ (tvName tvb, tvb_kind)
| (tvb, mb_vis_arg_ki) <- zip tvbs mb_vis_arg_kis
, Just tvb_kind <- [mb_vis_arg_ki <|> tvb_kind_maybe tvb]
]
= firstMatch (find_assoc_type_kind n cls_tvb_kind_map) sub_decs
match_kind_sig n _ dec = find_kind_sig n dec
find_kind_sig :: Name -> Dec -> Maybe Kind
#if __GLASGOW_HASKELL__ >= 809
find_kind_sig n (KiSigD n' ki)
| n `nameMatches` n' = Just ki
#endif
find_kind_sig _ _ = Nothing
match_cusk :: Name -> Dec -> Maybe Kind
#if __GLASGOW_HASKELL__ >= 800
match_cusk n (DataD _ n' tvbs m_ki _ _)
| n `nameMatches` n'
= datatype_kind tvbs m_ki
match_cusk n (NewtypeD _ n' tvbs m_ki _ _)
| n `nameMatches` n'
= datatype_kind tvbs m_ki
match_cusk n (DataFamilyD n' tvbs m_ki)
| n `nameMatches` n'
= open_ty_fam_kind tvbs m_ki
match_cusk n (OpenTypeFamilyD (TypeFamilyHead n' tvbs res_sig _))
| n `nameMatches` n'
= open_ty_fam_kind tvbs (res_sig_to_kind res_sig)
match_cusk n (ClosedTypeFamilyD (TypeFamilyHead n' tvbs res_sig _) _)
| n `nameMatches` n'
= closed_ty_fam_kind tvbs (res_sig_to_kind res_sig)
#else
match_cusk n (DataD _ n' tvbs _ _)
| n `nameMatches` n'
= datatype_kind tvbs Nothing
match_cusk n (NewtypeD _ n' tvbs _ _)
| n `nameMatches` n'
= datatype_kind tvbs Nothing
match_cusk n (FamilyD _ n' tvbs m_ki)
| n `nameMatches` n'
= open_ty_fam_kind tvbs m_ki
match_cusk n (ClosedTypeFamilyD n' tvbs m_ki _)
| n `nameMatches` n'
= closed_ty_fam_kind tvbs m_ki
#endif
match_cusk n (TySynD n' tvbs rhs)
| n `nameMatches` n'
= ty_syn_kind tvbs rhs
match_cusk n (ClassD _ n' tvbs _ sub_decs)
| n `nameMatches` n'
= class_kind tvbs
|
all tvb_is_kinded tvbs
, let cls_tvb_kind_map = Map.fromList [ (tvName tvb, tvb_kind)
| tvb <- tvbs
, Just tvb_kind <- [tvb_kind_maybe tvb]
]
= firstMatch (find_assoc_type_kind n cls_tvb_kind_map) sub_decs
match_cusk _ _ = Nothing
find_assoc_type_kind :: Name -> Map Name Kind -> Dec -> Maybe Kind
find_assoc_type_kind n cls_tvb_kind_map sub_dec =
case sub_dec of
#if __GLASGOW_HASKELL__ >= 800
DataFamilyD n' tf_tvbs m_ki
| n `nameMatches` n'
-> build_kind (map ascribe_tf_tvb_kind tf_tvbs) (default_res_ki m_ki)
OpenTypeFamilyD (TypeFamilyHead n' tf_tvbs res_sig _)
| n `nameMatches` n'
-> build_kind (map ascribe_tf_tvb_kind tf_tvbs)
(default_res_ki $ res_sig_to_kind res_sig)
#else
FamilyD _ n' tf_tvbs m_ki
| n `nameMatches` n'
-> build_kind (map ascribe_tf_tvb_kind tf_tvbs) (default_res_ki m_ki)
#endif
_ -> Nothing
where
ascribe_tf_tvb_kind :: TyVarBndr -> TyVarBndr
ascribe_tf_tvb_kind tvb =
case tvb of
KindedTV{} -> tvb
PlainTV tvn -> KindedTV tvn $ fromMaybe StarT $ Map.lookup tvn cls_tvb_kind_map
datatype_kind :: [TyVarBndr] -> Maybe Kind -> Maybe Kind
datatype_kind tvbs m_ki =
whenAlt (all tvb_is_kinded tvbs && ki_fvs_are_bound) $
build_kind tvbs (default_res_ki m_ki)
where
ki_fvs_are_bound :: Bool
ki_fvs_are_bound =
let ki_fvs = Set.fromList $ foldMap freeVariables m_ki
tvb_vars = Set.fromList $ freeVariables $ map tvbToTypeWithSig tvbs
in ki_fvs `Set.isSubsetOf` tvb_vars
class_kind :: [TyVarBndr] -> Maybe Kind
class_kind tvbs = whenAlt (all tvb_is_kinded tvbs) $
build_kind tvbs ConstraintT
open_ty_fam_kind :: [TyVarBndr] -> Maybe Kind -> Maybe Kind
open_ty_fam_kind tvbs m_ki =
build_kind (map default_tvb tvbs) (default_res_ki m_ki)
closed_ty_fam_kind :: [TyVarBndr] -> Maybe Kind -> Maybe Kind
closed_ty_fam_kind tvbs m_ki =
case m_ki of
Just ki -> whenAlt (all tvb_is_kinded tvbs) $
build_kind tvbs ki
Nothing -> Nothing
ty_syn_kind :: [TyVarBndr] -> Type -> Maybe Kind
ty_syn_kind tvbs rhs =
case rhs of
SigT _ ki -> whenAlt (all tvb_is_kinded tvbs) $
build_kind tvbs ki
_ -> Nothing
build_kind :: [TyVarBndr] -> Kind -> Maybe Kind
build_kind arg_kinds res_kind =
fmap quantifyType $ fst $
foldr go (Just res_kind, Set.fromList (freeVariables res_kind)) arg_kinds
where
go :: TyVarBndr -> (Maybe Kind, Set Name) -> (Maybe Kind, Set Name)
go tvb (res, res_fvs) =
case tvb of
PlainTV n
-> ( if n `Set.member` res_fvs
then forall_vis tvb res
else Nothing
, res_fvs
)
KindedTV n k
-> ( if n `Set.member` res_fvs
then forall_vis tvb res
else fmap (ArrowT `AppT` k `AppT`) res
, Set.fromList (freeVariables k) `Set.union` res_fvs
)
forall_vis :: TyVarBndr -> Maybe Kind -> Maybe Kind
#if __GLASGOW_HASKELL__ >= 809
forall_vis tvb m_ki = fmap (ForallVisT [tvb]) m_ki
#else
forall_vis _ _ = Nothing
#endif
tvb_is_kinded :: TyVarBndr -> Bool
tvb_is_kinded = isJust . tvb_kind_maybe
tvb_kind_maybe :: TyVarBndr -> Maybe Kind
tvb_kind_maybe PlainTV{} = Nothing
tvb_kind_maybe (KindedTV _ k) = Just k
vis_arg_kind_maybe :: VisFunArg -> Maybe Kind
vis_arg_kind_maybe (VisFADep tvb) = tvb_kind_maybe tvb
vis_arg_kind_maybe (VisFAAnon k) = Just k
default_tvb :: TyVarBndr -> TyVarBndr
default_tvb (PlainTV n) = KindedTV n StarT
default_tvb tvb@KindedTV{} = tvb
default_res_ki :: Maybe Kind -> Kind
default_res_ki = fromMaybe StarT
#if __GLASGOW_HASKELL__ >= 800
res_sig_to_kind :: FamilyResultSig -> Maybe Kind
res_sig_to_kind NoSig = Nothing
res_sig_to_kind (KindSig k) = Just k
res_sig_to_kind (TyVarSig tvb) = tvb_kind_maybe tvb
#endif
whenAlt :: Alternative f => Bool -> f a -> f a
whenAlt b fa = if b then fa else empty
lookupValueNameWithLocals :: DsMonad q => String -> q (Maybe Name)
lookupValueNameWithLocals = lookupNameWithLocals False
lookupTypeNameWithLocals :: DsMonad q => String -> q (Maybe Name)
lookupTypeNameWithLocals = lookupNameWithLocals True
lookupNameWithLocals :: DsMonad q => Bool -> String -> q (Maybe Name)
lookupNameWithLocals ns s = do
mb_name <- qLookupName ns s
case mb_name of
j_name@(Just{}) -> return j_name
Nothing -> consult_locals
where
built_name = mkName s
consult_locals = do
decs <- localDeclarations
let mb_infos = map (reifyInDec built_name decs) decs
infos = catMaybes mb_infos
return $ firstMatch (if ns then find_type_name
else find_value_name) infos
find_type_name, find_value_name :: Named Info -> Maybe Name
find_type_name (n, info) =
case infoNameSpace info of
TcClsName -> Just n
VarName -> Nothing
DataName -> Nothing
find_value_name (n, info) =
case infoNameSpace info of
VarName -> Just n
DataName -> Just n
TcClsName -> Nothing
mkDataNameWithLocals :: DsMonad q => String -> q Name
mkDataNameWithLocals = mkNameWith lookupValueNameWithLocals mkNameG_d
mkTypeNameWithLocals :: DsMonad q => String -> q Name
mkTypeNameWithLocals = mkNameWith lookupTypeNameWithLocals mkNameG_tc
reifyNameSpace :: DsMonad q => Name -> q (Maybe NameSpace)
reifyNameSpace n@(Name _ nf) =
case nf of
NameG ns _ _ -> pure $ Just ns
_ -> do mb_info <- reifyWithLocals_maybe n
pure $ fmap infoNameSpace mb_info
infoNameSpace :: Info -> NameSpace
infoNameSpace info =
case info of
ClassI{} -> TcClsName
TyConI{} -> TcClsName
FamilyI{} -> TcClsName
PrimTyConI{} -> TcClsName
TyVarI{} -> TcClsName
ClassOpI{} -> VarName
VarI{} -> VarName
DataConI{} -> DataName
#if __GLASGOW_HASKELL__ >= 801
PatSynI{} -> DataName
#endif