Use OPTIONS rather than OPTIONS_GHC for pragmas
[ghc-hetmet.git] / compiler / deSugar / DsForeign.lhs
index e7d5c39..45eb813 100644 (file)
@@ -6,6 +6,13 @@
 Desugaring foreign declarations (see also DsCCall).
 
 \begin{code}
+{-# OPTIONS -w #-}
+-- The above warning supression flag is a temporary kludge.
+-- While working on this module you are encouraged to remove it and fix
+-- any warnings in the module. See
+--     http://hackage.haskell.org/trac/ghc/wiki/CodingStyle#Warnings
+-- for details
+
 module DsForeign ( dsForeigns ) where
 
 #include "HsVersions.h"
@@ -40,6 +47,7 @@ import Outputable
 import FastString
 
 import Data.Maybe
+import Data.List
 \end{code}
 
 Desugaring of @foreign@ declarations is naturally split up into
@@ -64,32 +72,31 @@ dsForeigns :: [LForeignDecl Id]
 dsForeigns [] 
   = returnDs (NoStubs, [])
 dsForeigns fos
-  = foldlDs combine (ForeignStubs empty empty [] [], []) fos
- where
-  combine stubs (L loc decl) = putSrcSpanDs loc (combine1 stubs decl)
-
-  combine1 (ForeignStubs acc_h acc_c acc_hdrs acc_feb, acc_f) 
-          (ForeignImport id _ spec)
+  = do 
+    fives <- mapM do_ldecl fos
+    let
+        (hs, cs, hdrs, idss, bindss) = unzip5 fives
+        fe_ids = concat idss
+        fe_init_code = map foreignExportInitialiser fe_ids
+    --
+    return (ForeignStubs 
+             (vcat hs)
+             (vcat cs $$ vcat fe_init_code)
+             (nub (concat hdrs)),
+           (concat bindss))
+  where
+   do_ldecl (L loc decl) = putSrcSpanDs loc (do_decl decl)
+            
+   do_decl (ForeignImport id _ spec)
     = traceIf (text "fi start" <+> ppr id)     `thenDs` \ _ ->
       dsFImport (unLoc id) spec                        `thenDs` \ (bs, h, c, mbhd) -> 
       traceIf (text "fi end" <+> ppr id)       `thenDs` \ _ ->
-      returnDs (ForeignStubs (h $$ acc_h)
-                            (c $$ acc_c)
-                            (addH mbhd acc_hdrs)
-                            acc_feb, 
-               bs ++ acc_f)
-
-  combine1 (ForeignStubs acc_h acc_c acc_hdrs acc_feb, acc_f) 
-          (ForeignExport (L _ id) _ (CExport (CExportStatic ext_nm cconv)))
+      returnDs (h, c, maybeToList mbhd, [], bs)
+
+   do_decl (ForeignExport (L _ id) _ (CExport (CExportStatic ext_nm cconv)))
     = dsFExport id (idType id) 
                ext_nm cconv False                 `thenDs` \(h, c, _, _) ->
-      returnDs (ForeignStubs (h $$ acc_h) (c $$ acc_c) acc_hdrs (id:acc_feb), 
-               acc_f)
-
-  addH Nothing  ls = ls
-  addH (Just e) ls
-   | e `elem` ls = ls
-   | otherwise   = e:ls
+      returnDs (h, c, [], [id], [])
 \end{code}
 
 
@@ -282,8 +289,9 @@ dsFExport fn_id ty ext_name cconv isDyn
        -- If it's IO t, return         (t, True)
        -- If it's plain t, return      (t, False)
      (case tcSplitIOType_maybe orig_res_ty of
-       Just (ioTyCon, res_ty) -> returnDs (res_ty, True)
+       Just (ioTyCon, res_ty, co) -> returnDs (res_ty, True)
                -- The function already returns IO t
+               -- ToDo: what about the coercion?
        Nothing                -> returnDs (orig_res_ty, False) 
                -- The function returns t
      )                                 `thenDs` \ (res_ty,             -- t
@@ -339,7 +347,6 @@ dsFExportDynamic id cconv
      dsLookupGlobalId newStablePtrName         `thenDs` \ newStablePtrId ->
      dsLookupTyCon stablePtrTyConName          `thenDs` \ stable_ptr_tycon ->
      let
-       mk_stbl_ptr_app = mkApps (Var newStablePtrId) [ Type arg_ty, Var cback ]
        stable_ptr_ty   = mkTyConApp stable_ptr_tycon [arg_ty]
        export_ty       = mkFunTy stable_ptr_ty arg_ty
      in
@@ -348,12 +355,6 @@ dsFExportDynamic id cconv
      dsFExport id export_ty fe_nm cconv True   
                `thenDs` \ (h_code, c_code, arg_reps, args_size) ->
      let
-      stbl_app cont ret_ty = mkApps (Var bindIOId)
-                                   [ Type stable_ptr_ty
-                                   , Type ret_ty       
-                                   , mk_stbl_ptr_app
-                                   , cont
-                                   ]
        {-
         The arguments to the external function which will
        create a little bit of (template) code on the fly
@@ -384,18 +385,19 @@ dsFExportDynamic id cconv
                      _           -> Nothing
 
      in
-     dsCCall adjustor adj_args PlayRisky io_res_ty     `thenDs` \ ccall_adj ->
+     dsCCall adjustor adj_args PlayRisky (mkTyConApp io_tc [res_ty])  `thenDs` \ ccall_adj ->
        -- PlayRisky: the adjustor doesn't allocate in the Haskell heap or do a callback
-     let ccall_adj_ty = exprType ccall_adj
-         ccall_io_adj = mkLams [stbl_value]                 $
-#ifdef DEBUG
-                       pprTrace "DsForeign: why is there an unsafeCoerce here?" (text "") $
-#endif
-                       (Cast ccall_adj (mkUnsafeCoercion ccall_adj_ty io_res_ty ))
 
-         io_app = mkLams tvs    $
-                 mkLams [cback] $
-                 stbl_app ccall_io_adj res_ty
+     let io_app = mkLams tvs               $
+                 Lam cback                 $          
+                 mkCoerceI (mkSymCoI co)   $
+                 mkApps (Var bindIOId)
+                        [ Type stable_ptr_ty
+                        , Type res_ty       
+                        , mkApps (Var newStablePtrId) [ Type arg_ty, Var cback ]
+                        , Lam stbl_value ccall_adj
+                        ]
+
         fed = (id `setInlinePragma` NeverActive, io_app)
                -- Never inline the f.e.d. function, because the litlit
                -- might not be in scope in other modules.
@@ -403,11 +405,12 @@ dsFExportDynamic id cconv
      returnDs ([fed], h_code, c_code)
 
  where
-  ty                   = idType id
-  (tvs,sans_foralls)   = tcSplitForAllTys ty
-  ([arg_ty], io_res_ty)        = tcSplitFunTys sans_foralls
-  [res_ty]             = tcTyConAppArgs io_res_ty
-       -- Must use tcSplit* to see the (IO t), which is a newtype
+  ty                      = idType id
+  (tvs,sans_foralls)      = tcSplitForAllTys ty
+  ([arg_ty], fn_res_ty)           = tcSplitFunTys sans_foralls
+  Just (io_tc, res_ty, co) = tcSplitIOType_maybe fn_res_ty
+       -- Must have an IO type; hence Just
+       -- co : fn_res_ty ~ IO res_ty
 
 toCName :: Id -> String
 toCName i = showSDoc (pprCode CStyle (ppr (idName i)))
@@ -509,28 +512,6 @@ mkFExportCBits c_nm maybe_target arg_htys res_hty is_IO_res_ty cc
           Just hs_fn -> text "extern StgClosure " <> ppr hs_fn <> text "_closure" <> semi
 
    
-   -- Initialise foreign exports by registering a stable pointer from an
-   -- __attribute__((constructor)) function.
-   -- The alternative is to do this from stginit functions generated in
-   -- codeGen/CodeGen.lhs; however, stginit functions have a negative impact
-   -- on binary sizes and link times because the static linker will think that
-   -- all modules that are imported directly or indirectly are actually used by
-   -- the program.
-   -- (this is bad for big umbrella modules like Graphics.Rendering.OpenGL)
-
-  initialiser
-     = case maybe_target of
-          Nothing -> empty
-          Just hs_fn ->
-            vcat
-             [ text "static void stginit_export_" <> ppr hs_fn
-                  <> text "() __attribute__((constructor));"
-             , text "static void stginit_export_" <> ppr hs_fn <> text "()"
-             , braces (text "getStablePtr"
-                <> parens (text "(StgPtr) &" <> ppr hs_fn <> text "_closure")
-                <> semi)
-             ]
-
   -- finally, the whole darn thing
   c_bits =
     space $$
@@ -563,8 +544,28 @@ mkFExportCBits c_nm maybe_target arg_htys res_hty is_IO_res_ty cc
      ,   if res_hty_is_unit then empty
             else text "return cret;"
      , rbrace
-     ] $$
-    initialiser
+     ]
+
+
+foreignExportInitialiser :: Id -> SDoc
+foreignExportInitialiser hs_fn =
+   -- Initialise foreign exports by registering a stable pointer from an
+   -- __attribute__((constructor)) function.
+   -- The alternative is to do this from stginit functions generated in
+   -- codeGen/CodeGen.lhs; however, stginit functions have a negative impact
+   -- on binary sizes and link times because the static linker will think that
+   -- all modules that are imported directly or indirectly are actually used by
+   -- the program.
+   -- (this is bad for big umbrella modules like Graphics.Rendering.OpenGL)
+   vcat
+    [ text "static void stginit_export_" <> ppr hs_fn
+         <> text "() __attribute__((constructor));"
+    , text "static void stginit_export_" <> ppr hs_fn <> text "()"
+    , braces (text "getStablePtr"
+       <> parens (text "(StgPtr) &" <> ppr hs_fn <> text "_closure")
+       <> semi)
+    ]
+
 
 -- NB. the calculation here isn't strictly speaking correct.
 -- We have a primitive Haskell type (eg. Int#, Double#), and