import CoreSyn
-import DsCCall ( dsCCall, mkCCall, boxResult, unboxArg )
+import DsCCall ( dsCCall, mkCCall, boxResult, unboxArg, resultWrapper )
import DsMonad
import HsSyn ( ExtName(..), ForeignDecl(..), isDynamicExtName, ForKind(..) )
import TysWiredIn ( unitTy, addrTy, stablePtrTyCon,
addrDataCon
)
+import TysPrim ( addrPrimTy )
import Unique ( Uniquable(..), hasKey,
ioTyConKey, deRefStablePtrIdKey, returnIOIdKey,
bindIOIdKey, makeStablePtrIdKey
)
import Outputable
+
+import Maybe ( fromJust )
\end{code}
Desugaring of @foreign@ declarations is naturally split up into
dsFImport i (idType i) uns ext_nm cconv `thenDs` \ bs ->
returnDs (bs ++ acc_fi, acc_fe, acc_h, acc_c)
| isForeignLabel =
- dsFLabel i ext_nm `thenDs` \ b ->
+ dsFLabel i (idType i) ext_nm `thenDs` \ b ->
returnDs (b:acc_fi, acc_fe, acc_h, acc_c)
| isDynamicExtName ext_nm =
dsFExportDynamic i (idType i) mod_name ext_nm cconv `thenDs` \ (fi,fe,h,c) ->
Foreign labels
\begin{code}
-dsFLabel :: Id -> ExtName -> DsM CoreBind
-dsFLabel nm ext_name = returnDs (NonRec nm fo_rhs)
+dsFLabel :: Id -> Type -> ExtName -> DsM CoreBind
+dsFLabel nm ty ext_name =
+ ASSERT(fromJust res_ty == addrPrimTy) -- typechecker ensures this
+ returnDs (NonRec nm (fo_rhs (mkLit (MachLabel enm))))
where
- fo_rhs = mkConApp addrDataCon [mkLit (MachLabel enm)]
+ (res_ty, fo_rhs) = resultWrapper ty
enm = extNameStatic ext_name
\end{code}
fe_ext_name = ExtName (_PK_ fe_nm) Nothing
in
dsFExport i export_ty mod_name fe_ext_name cconv True
- `thenDs` \ (fe@(NonRec fe_helper fe_expr), h_code, c_code) ->
+ `thenDs` \ (fe@(NonRec fe_helper fe_expr), h_code, c_code) ->
newSysLocalDs arg_ty `thenDs` \ cback ->
dsLookupGlobalValue makeStablePtrIdKey `thenDs` \ makeStablePtrId ->
let
-- (probably in the RTS.)
adjustor = SLIT("createAdjustor")
in
- dsCCall adjustor adj_args False False ioAddrTy `thenDs` \ ccall_adj ->
+ dsCCall adjustor adj_args False False io_res_ty `thenDs` \ ccall_adj ->
let ccall_adj_ty = exprType ccall_adj
ccall_io_adj = mkLams [stbl_value] $
Note (Coerce io_res_ty (unUsgTy ccall_adj_ty))
in
let io_app = mkLams tvs $
mkLams [cback] $
- stbl_app ccall_io_adj addrTy
+ stbl_app ccall_io_adj res_ty
in
-- Never inline the f.e.d. function, because the litlit might not be in scope
-- in other modules.
isFFIArgumentTy, -- :: Bool -> Type -> Bool
isFFIResultTy, -- :: Type -> Bool
isFFIExternalTy, -- :: Type -> Bool
+ isFFIDynResultTy, -- :: Type -> Bool
+ isFFILabelTy, -- :: Type -> Bool
isAddrTy, -- :: Type -> Bool
isForeignObjTy -- :: Type -> Bool
-- But we allow () as well
isFFIResultTy ty = checkRepTyCon (\tc -> tc == unitTyCon || legalIncomingTyCon tc) ty
+-- The result type of a foreign export dynamic must be either Addr, or
+-- a newtype of Addr.
+isFFIDynResultTy = checkRepTyCon (== addrTyCon)
+
+-- The type of a foreign label must be either Addr, or
+-- a newtype of Addr.
+isFFILabelTy = checkRepTyCon (== addrTyCon)
+
checkRepTyCon :: (TyCon -> Bool) -> Type -> Bool
-- look through newtypes
checkRepTyCon check_tc ty = checkTyCon check_tc (repType ty)
legalIncomingTyCon tc
| getUnique tc `elem` [ foreignObjTyConKey, byteArrayTyConKey, mutableByteArrayTyConKey ]
= False
+ -- It's also illegal to make foreign exports that take unboxed
+ -- arguments. The RTS API currently can't invoke such things. --SDM 7/2000
| otherwise
- = marshalableTyCon tc
+ = boxedMarshalableTyCon tc
legalOutgoingTyCon :: Bool -> TyCon -> Bool
-- Checks validity of types going from Haskell -> external world
marshalableTyCon tc
= (opt_GlasgowExts && isUnLiftedTyCon tc)
- || getUnique tc `elem` [ intTyConKey, int8TyConKey, int16TyConKey, int32TyConKey, int64TyConKey
+ || boxedMarshalableTyCon tc
+
+boxedMarshalableTyCon tc
+ = getUnique tc `elem` [ intTyConKey, int8TyConKey, int16TyConKey, int32TyConKey, int64TyConKey
, wordTyConKey, word8TyConKey, word16TyConKey, word32TyConKey, word64TyConKey
, floatTyConKey, doubleTyConKey
, addrTyConKey, charTyConKey, foreignObjTyConKey
import TcMonad
import TcEnv ( newLocalId )
import TcType ( tcSplitRhoTy, zonkTcTypeToType )
-import TcMonoType ( tcHsBoxedSigType )
+import TcMonoType ( tcHsSigType, tcHsBoxedSigType )
import TcHsSyn ( TcMonoBinds, TypecheckedForeignDecl,
TcForeignExportDecl )
import TcExpr ( tcId, tcPolyExpr )
, splitForAllTys
)
import TysWiredIn ( isFFIArgumentTy, isFFIResultTy,
- isFFIExternalTy, isAddrTy
+ isFFIExternalTy, isAddrTy,
+ isFFIDynResultTy, isFFILabelTy
)
import Type ( Type )
import Unique
-- of the foreign type.
(_, t_ty) = splitForAllTys sig_ty
in
- check (isAddrTy t_ty) (illegalForeignTyErr False{-result-} sig_ty) `thenTc_`
+ check (isFFILabelTy t_ty)
+ (illegalForeignTyErr False{-result-} sig_ty) `thenTc_`
let i = (mkVanillaId nm sig_ty) in
returnTc (i, (ForeignDecl i FoLabel undefined ext_nm cconv src_loc))
tcAddSrcLoc src_loc $
tcAddErrCtxt (foreignDeclCtxt fo) $
- tcHsBoxedSigType hs_ty `thenTc` \ ty ->
+ tcHsSigType hs_ty `thenTc` \ ty ->
-- Check that the type has the right shape
-- and that the argument and result types are acceptable.
let
[arg] ->
case splitFunTys arg of
(arg_tys, res_ty) ->
- mapTc (checkForeignArg isFFIExternalTy) arg_tys `thenTc_`
- checkForeignRes True {-NonIO ok-} isFFIResultTy res_ty `thenTc_`
- checkForeignRes False {-Must be IO-} isAddrTy res
+ mapTc (checkForeignArg isFFIExternalTy) arg_tys `thenTc_`
+ checkForeignRes True {-NonIO ok-} isFFIResultTy res_ty `thenTc_`
+ checkForeignRes False {-Must be IO-} isFFIDynResultTy res
_ -> check False (illegalForeignTyErr True{-Arg-} ty)
| otherwise =
mapTc (checkForeignArg isFFIExternalTy) args `thenTc_`