
#14125: Bogus unacceptable type in foreign declaration. -------------------------------------+------------------------------------- Reporter: winter | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 8.2.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Description changed by winter: Old description:
I'm try to abstract FFI return type so that different errno scheme can work together, namely i create such a class:
{{{ class Integral (IOErrno r) => IOReturn r where -- | The errno type associated with 'r' data IOErrno r :: * -- | Is this return value indicate an error? isError :: Integral a => r a -> Bool -- | How can i get a errno then? getErrno :: Integral a => r a -> IO (IOErrno r) -- | Is this errno indicate interrupted blocking call? isInterrupt :: IOErrno r -> Bool -- | Is this errno indicate no data on a non-blocking device? isBlock :: IOErrno r -> Bool -- | OK, i want my return value if no errno. getReturn :: Integral a => r a -> a -- | Read the errno name for me. nameErrno :: IOErrno r -> IO String -- | Read the errno description for me. descErrno :: IOErrno r -> IO String }}}
But when i'm try to defining instance for it, such as a standard unix like:
{{{ newtype UnixReturn a = UnixReturn a deriving (Bounded, Enum, Eq, Integral, Num, Ord, Read, Real, Show, FiniteBits, Bits, Storable)
instance IOReturn UnixReturn where newtype IOErrno UnixReturn = UnixErrno CInt deriving (Bounded, Enum, Eq, Integral, Num, Ord, Read, Real, Show, FiniteBits, Bits, Storable) isError (UnixReturn r) = r == (-1) isInterrupt e = e == eINTR isBlock e = e == eAGAIN || e == eWOULDBLOCK getErrno _ = get_errno getReturn (UnixReturn r) = r nameErrno = return . nameUnixErrno descErrno e = strerror e >>= peekCString
eINTR = UnixErrno (CONST_EINTR) eWOULDBLOCK = UnixErrno (CONST_EWOULDBLOCK) ...
foreign import ccall unsafe "string.h" strerror :: IOErrno UnixReturn -> IO CString foreign import ccall unsafe "HsBase.h __hscore_get_errno" get_errno :: IO (IOErrno UnixReturn) }}}
I got a error on GHC 8.2:
{{{ System/IO/Exception.hs:282:1: error: • Unacceptable argument type in foreign declaration: ‘IOErrno UnixReturn’ cannot be marshalled in a foreign call • When checking declaration: foreign import ccall unsafe "string.h" strerror :: IOErrno UnixReturn -> IO CString | 282 | foreign import ccall unsafe "string.h" strerror :: IOErrno UnixReturn -> IO CString | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ System/IO/Exception.hs:283:1: error: • Unacceptable result type in foreign declaration: ‘IOErrno UnixReturn’ cannot be marshalled in a foreign call • When checking declaration: foreign import ccall unsafe "HsBase.h __hscore_get_errno" get_errno :: IO (IOErrno UnixReturn) | 283 | foreign import ccall unsafe "HsBase.h __hscore_get_errno" get_errno :: IO (IOErrno UnixReturn) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ }}}
And at every place i want mark my FFI return got this error too. e.g. following code compiles without problem on GHC < 8.2 (Note that the type and constructor are both available):
{{{
foreign import CALLCONV unsafe "HsNet.h recv" c_recv :: CInt -> Ptr Word8 -> CSize -> CInt -> IO (UnixReturn CSsize) }}}
But on GHC 8.2 a `Unacceptable result type in foreign declaration` is emitted. And I think it's a regression.
New description: I'm trying to abstract FFI return type so that different errno scheme can work together, namely i create such a class: {{{ class Integral (IOErrno r) => IOReturn r where -- | The errno type associated with 'r' data IOErrno r :: * -- | Is this return value indicate an error? isError :: Integral a => r a -> Bool -- | How can i get a errno then? getErrno :: Integral a => r a -> IO (IOErrno r) -- | Is this errno indicate interrupted blocking call? isInterrupt :: IOErrno r -> Bool -- | Is this errno indicate no data on a non-blocking device? isBlock :: IOErrno r -> Bool -- | OK, i want my return value if no errno. getReturn :: Integral a => r a -> a -- | Read the errno name for me. nameErrno :: IOErrno r -> IO String -- | Read the errno description for me. descErrno :: IOErrno r -> IO String }}} But when i'm try to defining instance for it, such as a standard unix like: {{{ newtype UnixReturn a = UnixReturn a deriving (Bounded, Enum, Eq, Integral, Num, Ord, Read, Real, Show, FiniteBits, Bits, Storable) instance IOReturn UnixReturn where newtype IOErrno UnixReturn = UnixErrno CInt deriving (Bounded, Enum, Eq, Integral, Num, Ord, Read, Real, Show, FiniteBits, Bits, Storable) isError (UnixReturn r) = r == (-1) isInterrupt e = e == eINTR isBlock e = e == eAGAIN || e == eWOULDBLOCK getErrno _ = get_errno getReturn (UnixReturn r) = r nameErrno = return . nameUnixErrno descErrno e = strerror e >>= peekCString eINTR = UnixErrno (CONST_EINTR) eWOULDBLOCK = UnixErrno (CONST_EWOULDBLOCK) ... foreign import ccall unsafe "string.h" strerror :: IOErrno UnixReturn -> IO CString foreign import ccall unsafe "HsBase.h __hscore_get_errno" get_errno :: IO (IOErrno UnixReturn) }}} I got a error on GHC 8.2: {{{ System/IO/Exception.hs:282:1: error: • Unacceptable argument type in foreign declaration: ‘IOErrno UnixReturn’ cannot be marshalled in a foreign call • When checking declaration: foreign import ccall unsafe "string.h" strerror :: IOErrno UnixReturn -> IO CString | 282 | foreign import ccall unsafe "string.h" strerror :: IOErrno UnixReturn -> IO CString | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ System/IO/Exception.hs:283:1: error: • Unacceptable result type in foreign declaration: ‘IOErrno UnixReturn’ cannot be marshalled in a foreign call • When checking declaration: foreign import ccall unsafe "HsBase.h __hscore_get_errno" get_errno :: IO (IOErrno UnixReturn) | 283 | foreign import ccall unsafe "HsBase.h __hscore_get_errno" get_errno :: IO (IOErrno UnixReturn) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ }}} And at every place i want mark my FFI return got this error too. e.g. following code compiles without problem on GHC < 8.2 (Note that the type and constructor are both available): {{{ foreign import CALLCONV unsafe "HsNet.h recv" c_recv :: CInt -> Ptr Word8 -> CSize -> CInt -> IO (UnixReturn CSsize) }}} But on GHC 8.2 a `Unacceptable result type in foreign declaration` is emitted. And I think it's a regression. -- -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/14125#comment:1 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler