[project @ 2002-02-06 20:52:51 by sof]
[ghc-hetmet.git] / ghc / compiler / deSugar / DsForeign.lhs
index 9c979a3..30f1089 100644 (file)
@@ -15,27 +15,23 @@ import CoreSyn
 import DsCCall         ( dsCCall, mkFCall, boxResult, unboxArg, resultWrapper )
 import DsMonad
 
-import HsSyn           ( ForeignDecl(..), FoExport(..), FoImport(..)  )
+import HsSyn           ( ForeignDecl(..), ForeignExport(..),
+                         ForeignImport(..), CImportSpec(..) )
 import TcHsSyn         ( TypecheckedForeignDecl )
 import CoreUtils       ( exprType, mkInlineMe )
 import Id              ( Id, idType, idName, mkVanillaGlobal, mkSysLocal,
                          setInlinePragma )
-import IdInfo          ( neverInlinePrag, vanillaIdInfo )
+import IdInfo          ( vanillaIdInfo )
 import Literal         ( Literal(..) )
 import Module          ( Module, moduleUserString )
 import Name            ( mkGlobalName, nameModule, nameOccName, getOccString, 
                          mkForeignExportOcc, isLocalName,
                          NamedThing(..),
                        )
-
-       -- Import Type not TcType; in this module we are generating code
-       -- to marshal representation types across to C
-import Type            ( splitTyConApp_maybe, funResultTy,
-                         splitFunTys, splitForAllTys, splitAppTy, 
-                         Type, mkFunTys, mkForAllTys, mkTyConApp,
-                         mkFunTy, applyTy, eqType, repType
-                       )
-import TcType          ( tcSplitForAllTys, tcSplitFunTys,
+import Type            ( repType, eqType )
+import TcType          ( Type, mkFunTys, mkForAllTys, mkTyConApp,
+                         mkFunTy, applyTy, 
+                         tcSplitForAllTys, tcSplitFunTys, tcTyConAppArgs,
                          tcSplitTyConApp_maybe, tcSplitAppTy,
                          tcFunResultTy
                        )
@@ -43,7 +39,8 @@ import TcType         ( tcSplitForAllTys, tcSplitFunTys,
 import ForeignCall     ( ForeignCall(..), CCallSpec(..), 
                          Safety(..), playSafe,
                          CExportSpec(..),
-                         CCallConv(..), ccallConvToInt
+                         CCallConv(..), ccallConvToInt,
+                         ccallConvAttribute
                        )
 import CStrings                ( CLabelString )
 import TysWiredIn      ( addrTy, unitTy, stablePtrTyCon )
@@ -51,8 +48,9 @@ import TysPrim                ( addrPrimTy )
 import PrelNames       ( hasKey, ioTyConKey, deRefStablePtrName, newStablePtrName,
                          bindIOName, returnIOName
                        )
+import BasicTypes      ( Activation( NeverActive ) )
+import ErrUtils         ( addShortWarnLocLine )
 import Outputable
-
 import Maybe           ( fromJust )
 \end{code}
 
@@ -82,17 +80,29 @@ dsForeigns :: Module
                                       -- "foreign exported" functions.
                  , SDoc              -- C stubs to use when calling
                                       -- "foreign exported" functions.
+                 , [FAST_STRING]     -- headers that need to be included
+                                     -- into C code generated for this module
                  )
 dsForeigns mod_name fos
-  = foldlDs combine ([], [], empty, empty) fos
+  = foldlDs combine ([], [], empty, empty, []) fos
  where
-  combine (acc_feb, acc_f, acc_h, acc_c) (ForeignImport id _ spec _) 
-    = dsFImport mod_name id spec       `thenDs` \ (bs, h, c) -> 
-      returnDs (acc_feb, bs ++ acc_f, h $$ acc_h, c $$ acc_c)
-
-  combine (acc_feb, acc_f, acc_h, acc_c) (ForeignExport id _ (CExport (CExportStatic ext_nm cconv)) _)
-    = dsFExport mod_name id (idType id) ext_nm cconv False     `thenDs` \ (feb, b, h, c) ->
-      returnDs (feb:acc_feb, b : acc_f, h $$ acc_h, c $$ acc_c)
+  combine (acc_feb, acc_f, acc_h, acc_c, acc_header) 
+         (ForeignImport id _ spec depr loc)
+    = dsFImport mod_name id spec                  `thenDs` \(bs, h, c, hd) -> 
+      warnDepr depr loc                                   `thenDs` \_              ->
+      returnDs (acc_feb, bs ++ acc_f, h $$ acc_h, c $$ acc_c, hd ++ acc_header)
+
+  combine (acc_feb, acc_f, acc_h, acc_c, acc_header) 
+         (ForeignExport id _ (CExport (CExportStatic ext_nm cconv)) depr loc)
+    = dsFExport mod_name id (idType id) 
+               ext_nm cconv False                 `thenDs` \(feb, b, h, c) ->
+      warnDepr depr loc                                   `thenDs` \_              ->
+      returnDs (feb:acc_feb, b : acc_f, h $$ acc_h, c $$ acc_c, acc_header)
+
+  warnDepr False _   = returnDs ()
+  warnDepr True  loc = dsWarn (addShortWarnLocLine loc msg)
+   where
+    msg = ptext SLIT("foreign declaration uses deprecated non-standard syntax")
 \end{code}
 
 
@@ -119,23 +129,38 @@ However, we create a worker/wrapper pair, thus:
 The strictness/CPR analyser won't do this automatically because it doesn't look
 inside returned tuples; but inlining this wrapper is a Really Good Idea 
 because it exposes the boxing to the call site.
-                       
 
 \begin{code}
 dsFImport :: Module
          -> Id
-         -> FoImport
+         -> ForeignImport
+         -> DsM ([Binding], SDoc, SDoc, [FAST_STRING])
+dsFImport modName id (CImport cconv safety header lib spec)
+  = dsCImport modName id spec cconv safety       `thenDs` \(ids, h, c) ->
+    returnDs (ids, h, c, if _NULL_ header then [] else [header])
+  -- FIXME: the `lib' field is needed for .NET ILX generation when invoking
+  --       routines that are external to the .NET runtime, but GHC doesn't
+  --       support such calls yet; if `_NULL_ lib', the value was not given
+dsFImport modName id (DNImport spec)
+  = dsFCall modName id (DNCall spec)             `thenDs` \(ids, h, c) ->
+    returnDs (ids, h, c, [])
+
+dsCImport :: Module
+         -> Id
+         -> CImportSpec
+         -> CCallConv
+         -> Safety
          -> DsM ([Binding], SDoc, SDoc)
-dsFImport mod_name lbl_id (LblImport ext_nm) 
- = ASSERT(fromJust res_ty `eqType` addrPrimTy) -- typechecker ensures this
-   returnDs ([(lbl_id, rhs)], empty, empty)
+dsCImport modName id (CLabel cid)       _     _
+ = ASSERT(fromJust resTy `eqType` addrPrimTy)    -- typechecker ensures this
+   returnDs ([(id, rhs)], empty, empty)
  where
-   (res_ty, fo_rhs) = resultWrapper (idType lbl_id)
-   rhs             = fo_rhs (mkLit (MachLabel ext_nm))
-
-dsFImport mod_name fn_id (CImport spec)     = dsFCall mod_name fn_id (CCall spec)
-dsFImport mod_name fn_id (DNImport spec)    = dsFCall mod_name fn_id (DNCall spec)
-dsFImport mod_name fn_id (CDynImport cconv) = dsFExportDynamic mod_name fn_id cconv
+   (resTy, foRhs) = resultWrapper (idType id)
+   rhs           = foRhs (mkLit (MachLabel cid))
+dsCImport modName id (CFunction target) cconv safety
+  = dsFCall modName id (CCall (CCallSpec target cconv safety))
+dsCImport modName id CWrapper           cconv _
+  = dsFExportDynamic modName id cconv
 \end{code}
 
 
@@ -151,6 +176,8 @@ dsFCall mod_Name fn_id fcall
        ty                   = idType fn_id
        (tvs, fun_ty)        = tcSplitForAllTys ty
        (arg_tys, io_res_ty) = tcSplitFunTys fun_ty
+               -- Must use tcSplit* functions because we want to 
+               -- see that (IO t) in the corner
     in
     newSysLocalsDs arg_tys                     `thenDs` \ args ->
     mapAndUnzipDs unboxArg (map Var args)      `thenDs` \ (val_args, arg_wrappers) ->
@@ -225,6 +252,9 @@ dsFExport mod_name fn_id ty ext_name cconv isDyn
        -- If it's IO t, return         (\x.x,          IO t, t)
        -- If it's plain t, return      (\x.returnIO x, IO t, t)
      (case tcSplitTyConApp_maybe orig_res_ty of
+       -- We must use tcSplit here so that we see the (IO t) in
+       -- the type.  [IO t is transparent to plain splitTyConApp.]
+
        Just (ioTyCon, [res_ty])
              -> ASSERT( ioTyCon `hasKey` ioTyConKey )
                        -- The function already returns IO t
@@ -303,15 +333,19 @@ dsFExport mod_name fn_id ty ext_name cconv isDyn
   where
    (tvs,sans_foralls)          = tcSplitForAllTys ty
    (fe_arg_tys', orig_res_ty)  = tcSplitFunTys sans_foralls
-
-   (_, stbl_ptr_ty')           = tcSplitForAllTys stbl_ptr_ty
-   (_, stbl_ptr_to_ty)         = tcSplitAppTy stbl_ptr_ty'
+       -- We must use tcSplits here, because we want to see 
+       -- the (IO t) in the corner of the type!
 
    fe_arg_tys | isDyn    = tail fe_arg_tys'
              | otherwise = fe_arg_tys'
 
    stbl_ptr_ty | isDyn     = head fe_arg_tys'
               | otherwise = error "stbl_ptr_ty"
+
+   (_, stbl_ptr_ty')           = tcSplitForAllTys stbl_ptr_ty
+   (_, stbl_ptr_to_ty)         = tcSplitAppTy stbl_ptr_ty'
+       -- Again, stable pointers are just newtypes, 
+       -- so we must see them!  Hence tcSplit*
 \end{code}
 
 @foreign export dynamic@ lets you dress up Haskell IO actions
@@ -388,18 +422,19 @@ dsFExportDynamic mod_name id cconv
          io_app = mkLams tvs    $
                  mkLams [cback] $
                  stbl_app ccall_io_adj res_ty
-        fed = (id `setInlinePragma` neverInlinePrag, io_app)
+        fed = (id `setInlinePragma` NeverActive, io_app)
                -- Never inline the f.e.d. function, because the litlit
                -- might not be in scope in other modules.
      in
      returnDs ([fed, fe], h_code, c_code)
 
  where
-  ty                              = idType id
-  (tvs,sans_foralls)              = tcSplitForAllTys ty
-  ([arg_ty], io_res_ty)                   = tcSplitFunTys sans_foralls
-  Just (ioTyCon, [res_ty])        = tcSplitTyConApp_maybe io_res_ty
-  export_ty                       = mkFunTy (mkTyConApp stablePtrTyCon [arg_ty]) arg_ty
+  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
+  export_ty            = mkFunTy (mkTyConApp stablePtrTyCon [arg_ty]) arg_ty
 
 toCName :: Id -> String
 toCName i = showSDoc (pprCode CStyle (ppr (idName i)))
@@ -455,14 +490,14 @@ fexportEntry mod_nm c_nm helper args res_ty cc isDyn = (header_bits, c_bits)
 
   cParamTypes  = map showStgType real_args
 
-  res_ty_is_unit = res_ty `eqType` unitTy
+  res_ty_is_unit = res_ty `eqType` unitTy      -- Look through any newtypes
 
   cResType | res_ty_is_unit = text "void"
           | otherwise      = showStgType res_ty
 
   pprCconv = case cc of
                CCallConv   -> empty
-               StdCallConv -> ppr cc
+               StdCallConv -> text (ccallConvAttribute cc)
      
   declareResult  = text "HaskellObj ret;"
 
@@ -503,7 +538,7 @@ showStgType t = text "Hs" <> text (showFFIType t)
 showFFIType :: Type -> String
 showFFIType t = getOccString (getName tc)
  where
-  tc = case splitTyConApp_maybe (repType t) of
+  tc = case tcSplitTyConApp_maybe (repType t) of
            Just (tc,_) -> tc
            Nothing     -> pprPanic "showFFIType" (ppr t)
 \end{code}