[project @ 1996-01-08 20:28:12 by partain]
[ghc-hetmet.git] / ghc / compiler / specialise / SpecTyFuns.lhs
diff --git a/ghc/compiler/specialise/SpecTyFuns.lhs b/ghc/compiler/specialise/SpecTyFuns.lhs
new file mode 100644 (file)
index 0000000..39fbd17
--- /dev/null
@@ -0,0 +1,293 @@
+%
+% (c) The GRASP/AQUA Project, Glasgow University, 1993-1995
+%
+\section[Specialise]{Stamping out overloading, and (optionally) polymorphism}
+
+\begin{code}
+#include "HsVersions.h"
+
+module SpecTyFuns (
+       specialiseCallTys,
+       ConstraintVector(..),
+       mkConstraintVector,
+       isUnboxedSpecialisation,
+
+       specialiseConstrTys,
+       mkSpecialisedCon,
+
+       argTysMatchSpecTys_error,
+
+       pprSpecErrs,
+
+       Maybe(..), Pretty(..), UniType
+    ) where
+
+import AbsUniType
+import Bag             ( Bag, isEmptyBag, bagToList )
+import FiniteMap       ( FiniteMap, emptyFM, addListToFM_C,
+                         keysFM, lookupWithDefaultFM
+                       )
+import Id              ( mkSameSpecCon, getIdUniType,
+                         isDictFunId, isConstMethodId, Id )
+import Maybes  
+import Outputable
+import Pretty
+import Util
+\end{code}
+
+%************************************************************************
+%*                                                                     *
+\subsection[@specialiseTys@]{Determine specialising types}
+%*                                                                     *
+%************************************************************************
+
+@specialiseCallTys@ works out which type args don't need to be specialised on,
+based on flags, the overloading constraint vector, and the types.
+
+\begin{code}
+specialiseCallTys :: Bool              -- Specialise on all type args
+                 -> Bool               -- Specialise on unboxed type args
+                 -> Bool               -- Specialise on overloaded type args
+                 -> ConstraintVector   -- Tells which type args are overloaded
+                 -> [UniType]          -- Type args
+                 -> [Maybe UniType]    -- Nothings replace non-specialised type args
+
+specialiseCallTys True _ _ cvec tys
+  = map Just tys
+specialiseCallTys False spec_unboxed spec_overloading cvec tys
+  = zipWith spec_ty_other cvec tys
+  where
+    spec_ty_other c ty | (spec_unboxed && isUnboxedDataType ty)
+                        || (spec_overloading && c)
+                        = Just ty
+                      | otherwise
+                         = Nothing
+
+type ConstraintVector = [Bool] -- True for constrained tyvar, false otherwise
+
+mkConstraintVector :: [TyVarTemplate] 
+                  -> [(Class,TyVarTemplate)]
+                  -> ConstraintVector
+
+mkConstraintVector tyvars class_tyvar_pairs
+  = [tyvar `elem` constrained_tyvars | tyvar <- tyvars]
+  where
+    constrained_tyvars   = map snd class_tyvar_pairs   -- May contain dups
+\end{code}
+
+\begin{code}
+isUnboxedSpecialisation :: [Maybe UniType] -> Bool
+isUnboxedSpecialisation tys
+  = any is_unboxed tys
+  where
+    is_unboxed (Just ty) = isUnboxedDataType ty
+    is_unboxed Nothing   = False
+\end{code}
+
+@specialiseConstrTys@ works out which type args don't need to be
+specialised on. We only speciailise on unboxed types.
+
+\begin{code}
+specialiseConstrTys :: [UniType]
+                   -> [Maybe UniType]
+
+specialiseConstrTys tys
+  = map maybe_unboxed_ty tys
+  where
+    maybe_unboxed_ty ty = case isUnboxedDataType ty of
+                           True  -> Just ty
+                           False -> Nothing
+\end{code}
+
+\begin{code}
+mkSpecialisedCon :: Id -> [UniType] -> Id
+mkSpecialisedCon con tys
+  = if spec_reqd
+    then mkSameSpecCon spec_tys con
+    else con
+  where
+    spec_tys  = specialiseConstrTys tys
+    spec_reqd = maybeToBool (firstJust spec_tys)
+\end{code}
+
+@argTysMatchSpecTys@ checks if a list of argument types is consistent
+with a list of specialising types. An error message is returned if not.
+\begin{code}
+argTysMatchSpecTys_error :: [Maybe UniType]
+                        -> [UniType] 
+                        -> Maybe Pretty
+argTysMatchSpecTys_error spec_tys arg_tys
+  = if match spec_tys arg_tys
+    then Nothing
+    else Just (ppSep [ppStr "Spec and Arg Types Inconsistent:",
+                     ppStr "spectys=", ppSep [pprMaybeTy PprDebug ty | ty <- spec_tys],
+                     ppStr "argtys=", ppSep [pprParendUniType PprDebug ty | ty <- arg_tys]])
+  where
+    match (Nothing:spec_tys) (arg:arg_tys)
+      = not (isUnboxedDataType arg) &&
+        match spec_tys arg_tys
+    match (Just spec:spec_tys) (arg:arg_tys)
+      = case (cmpUniType True{-properly-} spec arg) of
+          EQ_   -> match spec_tys arg_tys
+          other -> False
+    match [] [] = True
+    match _  _  = False
+\end{code}
+
+@pprSpecErrs@ prints error and warning information
+about imported specialisations which do not exist.
+
+\begin{code}
+pprSpecErrs :: PprStyle
+           -> (Bag (Id,[Maybe UniType]))       -- errors
+           -> (Bag (Id,[Maybe UniType]))       -- warnings
+           -> (Bag (TyCon,[Maybe UniType]))    -- errors
+           -> Pretty
+
+pprSpecErrs sty spec_errs spec_warn spec_tyerrs
+  | not any_errs && not any_warn
+  = ppNil
+
+  | otherwise
+  = ppAboves [if any_errs then ppAboves [
+                 ppStr "SPECIALISATION ERRORS (Essential):",
+                 ppAboves (map pp_module_errs use_modules),
+                 ppStr "***"
+                  ]
+             else
+                 ppNil,
+             if any_warn then ppAboves [
+                 ppStr "SPECIALISATION MESSAGES (Desirable):",
+                 ppAboves (map pp_module_warn use_modules),
+                 ppStr "***"
+                  ]
+             else
+                 ppNil
+            ]
+  where
+    any_errs = not (isEmptyBag spec_errs) || not (isEmptyBag spec_tyerrs)
+    any_warn = not (isEmptyBag spec_warn)
+
+    mk_module_fm errs_bag
+      = addListToFM_C (++) emptyFM errs_list
+      where
+        errs_list = map add_name (bagToList errs_bag)
+
+    add_name (id, tys) = (mod, [(name, id, tys)])
+                      where
+                        (mod,name) = getOrigName id
+
+    tyerrs_fm = mk_module_fm spec_tyerrs
+    errs_fm   = mk_module_fm spec_errs
+    warn_fm   = mk_module_fm spec_warn
+
+    module_names   = concat [keysFM errs_fm, keysFM warn_fm, keysFM tyerrs_fm]
+    sorted_modules = map head (equivClasses _CMP_STRING_ module_names)
+
+       -- Ensure any dfun instance specialisations (module _NIL_) are printed last
+       -- ToDo: Print instance specialisations with the instance module
+       --       This requires the module which defined the instance to be known:
+       --       add_name could then extract the instance module for a dfun id
+       --       and pp_dfun made a special case of pp_err
+    use_modules = if (head sorted_modules == _NIL_)
+                 then tail sorted_modules ++ [_NIL_]
+                 else sorted_modules
+
+
+    pp_module_errs :: FAST_STRING -> Pretty
+    pp_module_errs mod
+      | have_errs && mod == _NIL_ 
+       -- A _NIL_ module string corresponds to internal Ids
+       -- The only ones for which call instances should arise are
+       --   dfuns which correspond to instance specialisations
+      = ASSERT (null mod_tyerrs)
+        ppAboves [
+           ppStr "*** INSTANCES",
+           ppAboves (map (pp_dfun sty) mod_errs)
+            ]
+
+      | have_errs
+      = ppAboves [
+           pp_module mod,
+           ppAboves (map (pp_err sty) mod_errs),
+           ppAboves (map (pp_tyerr sty) mod_tyerrs)
+           ]
+
+      | otherwise
+      = ppNil
+
+      where
+        mod_tyerrs = lookupWithDefaultFM tyerrs_fm [] mod
+        mod_errs   = lookupWithDefaultFM errs_fm [] mod
+       have_errs  = not (null mod_tyerrs) || not (null mod_errs)
+
+
+    pp_module_warn :: FAST_STRING -> Pretty
+    pp_module_warn mod
+      | have_warn && mod == _NIL_
+       -- A _NIL_ module string corresponds to internal Ids
+       -- The only ones for which call instances should arise are
+       --   dfuns which correspond to instance specialisations
+      = ppAboves [
+           ppStr "*** INSTANCES",
+           ppAboves (map (pp_dfun sty) mod_warn)
+            ]
+
+      | have_warn
+      = ppAboves [
+           pp_module mod,
+           ppAboves (map (pp_err sty) mod_warn)
+            ]
+
+      | otherwise
+      = ppNil
+
+      where
+        mod_warn  = lookupWithDefaultFM warn_fm [] mod
+        have_warn = not (null mod_warn)
+
+
+pp_module mod
+  = ppCat [ppStr "*** module", ppPStr mod, ppStr "***"]
+
+
+pp_tyerr :: PprStyle -> (FAST_STRING, TyCon, [Maybe UniType]) -> Pretty
+
+pp_tyerr sty (_, tycon, tys)
+  = ppCat [ppStr "{-# SPECIALIZE data",
+          pprNonOp sty tycon, ppCat (map (pprParendUniType sty) spec_tys),
+          ppStr "#-}" ]
+  where
+    tvs = getTyConTyVarTemplates tycon
+    (spec_args, tv_maybes) = unzip (map choose_ty (tvs `zip` tys))
+    spec_tys = map (mkForallTy (catMaybes tv_maybes)) spec_args
+
+    choose_ty (tv, Nothing) = (mkTyVarTemplateTy tv, Just tv)
+    choose_ty (tv, Just ty) = (ty, Nothing)
+
+pp_err sty (_, id, tys)
+  = ppCat [ppStr "{-# SPECIALIZE",
+          pprNonOp sty id, ppStr "::",
+          pprUniType sty spec_ty,
+          ppStr "#-}" ]
+  where
+    spec_ty = specialiseTy (getIdUniType id) tys 100   -- HACK to drop all dicts!!!
+
+pp_dfun sty (_, id, tys)
+  | isDictFunId id
+  = ppCat [ppStr "{-# SPECIALIZE instance",
+          pprUniType sty spec_ty,
+          ppStr "#-}" ]
+  | isConstMethodId id
+  = pp_comment sty "OVERLOADED METHOD" id spec_ty
+  | otherwise
+  = pp_comment sty "HELP ..." id spec_ty
+  where
+    spec_ty = specialiseTy (getIdUniType id) tys 100   -- HACK to drop all dicts!!!
+
+pp_comment sty msg id spec_ty
+  = ppCat [ppStr "{-", ppStr msg,
+          pprNonOp sty id, ppStr "::",
+          pprUniType sty spec_ty,
+          ppStr "-}" ]
+\end{code}