+---------------------------------------------------------------------
+ FunTy
+ ~~~~~
+
+\begin{code}
+mkFunTy :: Type -> Type -> Type
+mkFunTy arg res = UASSERT2( isUTy arg && isUTy res, pprType arg <+> pprType res )
+ FunTy arg res
+
+mkFunTys :: [Type] -> Type -> Type
+mkFunTys tys ty = UASSERT2( all isUTy (ty:tys), fsep (map pprType (tys++[ty])) )
+ foldr FunTy ty tys
+
+splitFunTy :: Type -> (Type, Type)
+splitFunTy (FunTy arg res) = (arg, res)
+splitFunTy (NoteTy _ ty) = splitFunTy ty
+splitFunTy (PredTy p) = splitFunTy (predRepTy p)
+splitFunTy ty@(UsageTy _ _) = pprPanic "splitFunTy: UTy:" (pprType ty)
+
+splitFunTy_maybe :: Type -> Maybe (Type, Type)
+splitFunTy_maybe (FunTy arg res) = Just (arg, res)
+splitFunTy_maybe (NoteTy _ ty) = splitFunTy_maybe ty
+splitFunTy_maybe (PredTy p) = splitFunTy_maybe (predRepTy p)
+splitFunTy_maybe ty@(UsageTy _ _) = pprPanic "splitFunTy_maybe: UTy:" (pprType ty)
+splitFunTy_maybe other = Nothing
+
+splitFunTys :: Type -> ([Type], Type)
+splitFunTys ty = split [] ty ty
+ where
+ split args orig_ty (FunTy arg res) = split (arg:args) res res
+ split args orig_ty (NoteTy _ ty) = split args orig_ty ty
+ split args orig_ty (PredTy p) = split args orig_ty (predRepTy p)
+ split args orig_ty (UsageTy _ _) = pprPanic "splitFunTys: UTy:" (pprType orig_ty)
+ split args orig_ty ty = (reverse args, orig_ty)
+
+splitFunTysN :: String -> Int -> Type -> ([Type], Type)
+splitFunTysN msg orig_n orig_ty = split orig_n [] orig_ty orig_ty
+ where
+ split 0 args syn_ty ty = (reverse args, syn_ty)
+ split n args syn_ty (FunTy arg res) = split (n-1) (arg:args) res res
+ split n args syn_ty (NoteTy _ ty) = split n args syn_ty ty
+ split n args syn_ty (PredTy p) = split n args syn_ty (predRepTy p)
+ split n args syn_ty (UsageTy _ _) = pprPanic "splitFunTysN: UTy:" (pprType orig_ty)
+ split n args syn_ty ty = pprPanic ("splitFunTysN: " ++ msg) (int orig_n <+> pprType orig_ty)
+
+zipFunTys :: Outputable a => [a] -> Type -> ([(a,Type)], Type)
+zipFunTys orig_xs orig_ty = split [] orig_xs orig_ty orig_ty
+ where
+ split acc [] nty ty = (reverse acc, nty)
+ split acc (x:xs) nty (FunTy arg res) = split ((x,arg):acc) xs res res
+ split acc xs nty (NoteTy _ ty) = split acc xs nty ty
+ split acc xs nty (PredTy p) = split acc xs nty (predRepTy p)
+ split acc xs nty (UsageTy _ _) = pprPanic "zipFunTys: UTy:" (ppr orig_xs <+> pprType orig_ty)
+ split acc (x:xs) nty ty = pprPanic "zipFunTys" (ppr orig_xs <+> pprType orig_ty)
+
+funResultTy :: Type -> Type
+funResultTy (FunTy arg res) = res
+funResultTy (NoteTy _ ty) = funResultTy ty
+funResultTy (PredTy p) = funResultTy (predRepTy p)
+funResultTy (UsageTy _ ty) = funResultTy ty
+funResultTy ty = pprPanic "funResultTy" (pprType ty)
+
+funArgTy :: Type -> Type
+funArgTy (FunTy arg res) = arg
+funArgTy (NoteTy _ ty) = funArgTy ty
+funArgTy (PredTy p) = funArgTy (predRepTy p)
+funArgTy (UsageTy _ ty) = funArgTy ty
+funArgTy ty = pprPanic "funArgTy" (pprType ty)
+\end{code}
+
+
+---------------------------------------------------------------------
+ TyConApp
+ ~~~~~~~~
+
+\begin{code}
+mkTyConApp :: TyCon -> [Type] -> Type
+mkTyConApp tycon tys
+ | isFunTyCon tycon && length tys == 2
+ = case tys of
+ (ty1:ty2:_) -> FunTy (mkUTyM ty1) (mkUTyM ty2)
+
+ | otherwise
+ = ASSERT(not (isSynTyCon tycon))
+ UASSERT2( not (any isUTy tys), ppr tycon <+> fsep (map pprType tys) )
+ TyConApp tycon tys
+
+mkTyConTy :: TyCon -> Type
+mkTyConTy tycon = ASSERT( not (isSynTyCon tycon) )
+ TyConApp tycon []
+
+-- splitTyConApp "looks through" synonyms, because they don't
+-- mean a distinct type, but all other type-constructor applications
+-- including functions are returned as Just ..
+
+tyConAppTyCon :: Type -> TyCon
+tyConAppTyCon ty = case splitTyConApp_maybe ty of
+ Just (tc,_) -> tc
+ Nothing -> pprPanic "tyConAppTyCon" (pprType ty)
+
+tyConAppArgs :: Type -> [Type]
+tyConAppArgs ty = case splitTyConApp_maybe ty of
+ Just (_,args) -> args
+ Nothing -> pprPanic "tyConAppArgs" (pprType ty)
+
+splitTyConApp :: Type -> (TyCon, [Type])
+splitTyConApp ty = case splitTyConApp_maybe ty of
+ Just stuff -> stuff
+ Nothing -> pprPanic "splitTyConApp" (pprType ty)
+
+splitTyConApp_maybe :: Type -> Maybe (TyCon, [Type])
+splitTyConApp_maybe (TyConApp tc tys) = Just (tc, tys)
+splitTyConApp_maybe (FunTy arg res) = Just (funTyCon, [unUTy arg,unUTy res])
+splitTyConApp_maybe (NoteTy _ ty) = splitTyConApp_maybe ty
+splitTyConApp_maybe (PredTy p) = splitTyConApp_maybe (predRepTy p)
+splitTyConApp_maybe (UsageTy _ ty) = splitTyConApp_maybe ty
+splitTyConApp_maybe other = Nothing
+
+-- splitAlgTyConApp_maybe looks for
+-- *saturated* applications of *algebraic* data types
+-- "Algebraic" => newtype, data type, or dictionary (not function types)
+-- We return the constructors too, so there had better be some.
+
+splitAlgTyConApp_maybe :: Type -> Maybe (TyCon, [Type], [DataCon])
+splitAlgTyConApp_maybe (TyConApp tc tys)
+ | isAlgTyCon tc &&
+ tyConArity tc == length tys = Just (tc, tys, tyConDataCons tc)
+splitAlgTyConApp_maybe (NoteTy _ ty) = splitAlgTyConApp_maybe ty
+splitAlgTyConApp_maybe (PredTy p) = splitAlgTyConApp_maybe (predRepTy p)
+splitAlgTyConApp_maybe (UsageTy _ ty)= splitAlgTyConApp_maybe ty
+splitAlgTyConApp_maybe other = Nothing
+
+splitAlgTyConApp :: Type -> (TyCon, [Type], [DataCon])
+ -- Here the "algebraic" property is an *assertion*
+splitAlgTyConApp (TyConApp tc tys) = ASSERT( isAlgTyCon tc && tyConArity tc == length tys )
+ (tc, tys, tyConDataCons tc)
+splitAlgTyConApp (NoteTy _ ty) = splitAlgTyConApp ty
+splitAlgTyConApp (PredTy p) = splitAlgTyConApp (predRepTy p)
+splitAlgTyConApp (UsageTy _ ty) = splitAlgTyConApp ty
+#ifdef DEBUG
+splitAlgTyConApp ty = pprPanic "splitAlgTyConApp" (pprType ty)
+#endif
+\end{code}
+
+
+---------------------------------------------------------------------
+ SynTy
+ ~~~~~
+
+\begin{code}
+mkSynTy syn_tycon tys
+ = ASSERT( isSynTyCon syn_tycon )
+ ASSERT( length tyvars == length tys )
+ NoteTy (SynNote (TyConApp syn_tycon tys))
+ (substTy (mkTyVarSubst tyvars tys) body)
+ where
+ (tyvars, body) = getSynTyConDefn syn_tycon
+
+deNoteType :: Type -> Type
+ -- Remove synonyms, but not Preds
+deNoteType ty@(TyVarTy tyvar) = ty
+deNoteType (TyConApp tycon tys) = TyConApp tycon (map deNoteType tys)
+deNoteType (PredTy p) = PredTy (deNotePred p)
+deNoteType (NoteTy _ ty) = deNoteType ty
+deNoteType (AppTy fun arg) = AppTy (deNoteType fun) (deNoteType arg)
+deNoteType (FunTy fun arg) = FunTy (deNoteType fun) (deNoteType arg)
+deNoteType (ForAllTy tv ty) = ForAllTy tv (deNoteType ty)
+deNoteType (UsageTy u ty) = UsageTy u (deNoteType ty)
+
+deNotePred :: PredType -> PredType
+deNotePred (ClassP c tys) = ClassP c (map deNoteType tys)
+deNotePred (IParam n ty) = IParam n (deNoteType ty)
+\end{code}
+