[GHC] #14125: Bogus unacceptable type in foreign declaration.

GHC ghc-devs at haskell.org
Wed Aug 16 06:11:36 UTC 2017


#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


More information about the ghc-tickets mailing list