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

#14125: Bogus unacceptable type in foreign declaration. -------------------------------------+------------------------------------- Reporter: winter | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 8.2.1 Keywords: | Operating System: Unknown/Multiple Architecture: | Type of failure: None/Unknown Unknown/Multiple | Test Case: | Blocked By: Blocking: | Related Tickets: Differential Rev(s): | Wiki Page: -------------------------------------+------------------------------------- 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. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/14125 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#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

#14125: Bogus unacceptable type in foreign declaration. -------------------------------------+------------------------------------- Reporter: winter | Owner: (none) Type: bug | Status: new Priority: high | Milestone: Component: Compiler (FFI) | Version: 8.2.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Type of failure: GHC rejects | Unknown/Multiple valid program | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Changes (by RyanGlScott): * priority: normal => high * failure: None/Unknown => GHC rejects valid program * component: Compiler => Compiler (FFI) Comment: From what I can see, there are two different bugs being reported here: 1. You can't use newtype instances as marshallable argument types. That is, this should compile, but doesn't: {{{#!hs {-# LANGUAGE ForeignFunctionInterface #-} {-# LANGUAGE TypeFamilies #-} module Bug where import Foreign.C.String import Foreign.C.Types data UnixReturn data family IOErrno a newtype instance IOErrno UnixReturn = UnixErrno CInt foreign import ccall unsafe "string.h" strerror :: IOErrno UnixReturn -> IO CString }}} This is indeed a regression, as this code typechecks in 8.0.2 but not 8.2.1. I'll try to figure out which commit caused this. 2. You can't use newtypes as marshallable return types. However, I'm having trouble coming up with a minimal program which triggers the error you're claiming will happen on 8.2. I tried this: {{{#!hs {-# LANGUAGE ForeignFunctionInterface #-} module Bug where import Foreign import Foreign.C.Types import System.Posix.Types newtype UnixReturn a = UnixReturn a foreign import ccall unsafe "recv" c_recv :: CInt -> Ptr Word8 -> CSize -> CInt -> IO (UnixReturn CSsize) }}} But this typechecks on GHC 8.2, so there must be something that I'm missing. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/14125#comment:2 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#14125: Bogus unacceptable type in foreign declaration. -------------------------------------+------------------------------------- Reporter: winter | Owner: (none) Type: bug | Status: new Priority: high | Milestone: 8.2.2 Component: Compiler (FFI) | Version: 8.2.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Type of failure: GHC rejects | Unknown/Multiple valid program | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Changes (by RyanGlScott): * cc: simonpj (added) * milestone: => 8.2.2 Comment: So the commit that broke the program in item (1) in comment:2 is 3540d1e1a23926ce0a8a6ae83a36f5f6b2497ccf (`Avoid exponential blowup in FamInstEnv.normaliseType`). It's a fairly small commit, so I'm hoping that staring at the diff will reveal what changed to cause the program to go wrong. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/14125#comment:3 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#14125: Bogus unacceptable type in foreign declaration. -------------------------------------+------------------------------------- Reporter: winter | Owner: (none) Type: bug | Status: patch Priority: high | Milestone: 8.2.2 Component: Compiler (FFI) | Version: 8.2.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Type of failure: GHC rejects | Unknown/Multiple valid program | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Phab:D3865 Wiki Page: | -------------------------------------+------------------------------------- Changes (by RyanGlScott): * status: new => patch * differential: => Phab:D3865 Comment: I've submitted a fix for (1) at Phab:D3865. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/14125#comment:4 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#14125: Bogus unacceptable type in foreign declaration. -------------------------------------+------------------------------------- Reporter: winter | Owner: (none) Type: bug | Status: patch Priority: high | Milestone: 8.2.2 Component: Compiler (FFI) | Version: 8.2.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Type of failure: GHC rejects | Unknown/Multiple valid program | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Phab:D3865 Wiki Page: | -------------------------------------+------------------------------------- Comment (by winter): Well, the second case is very easy to create, just use newtype instance: {{{ {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE ForeignFunctionInterface #-} module Bug where import Foreign import Foreign.C.Types import System.Posix.Types class IOReturn (r :: * -> *) where -- | The errno type associated with 'r' data IOErrno r :: * newtype UnixReturn a = UnixReturn a instance IOReturn UnixReturn where newtype IOErrno UnixReturn = UnixErrno CInt foreign import ccall unsafe "HsBase.h __hscore_get_errno" get_errno :: IO (IOErrno UnixReturn) }}} {{{ [1 of 1] Compiling Bug ( Main.hs, Main.o ) Main.hs:20: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) | 20 | foreign import ccall unsafe "HsBase.h __hscore_get_errno" get_errno :: IO (IOErrno UnixReturn) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ }}} -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/14125#comment:5 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#14125: Bogus unacceptable type in foreign declaration. -------------------------------------+------------------------------------- Reporter: winter | Owner: (none) Type: bug | Status: patch Priority: high | Milestone: 8.2.2 Component: Compiler (FFI) | Version: 8.2.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Type of failure: GHC rejects | Unknown/Multiple valid program | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Phab:D3865 Wiki Page: | -------------------------------------+------------------------------------- Comment (by RyanGlScott): Indeed, I already have a test case for `IOErrno UnixReturn` in the Diff posted earlier (whether it's an argument type or result type isn't of much consequence, as they're normalized the same). To be clear, I was inquiring about this code from your original post. {{{#!hs foreign import CALLCONV unsafe "HsNet.h recv" c_recv :: CInt -> Ptr Word8 -> CSize -> CInt -> IO (UnixReturn CSsize) }}} I am unable to get this code to emit a `Unacceptable result type in foreign declaration` warning on GHC 8.2 like you claimed. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/14125#comment:6 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#14125: Bogus unacceptable type in foreign declaration. -------------------------------------+------------------------------------- Reporter: winter | Owner: (none) Type: bug | Status: patch Priority: high | Milestone: 8.2.2 Component: Compiler (FFI) | Version: 8.2.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Type of failure: GHC rejects | Unknown/Multiple valid program | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Phab:D3865 Wiki Page: | -------------------------------------+------------------------------------- Comment (by winter): My bad, I checked the orignal console output, and the problem just occurs when newtype instance involved. The original output is here: https://travis- ci.org/winterland1989/stdio/jobs/264713243 -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/14125#comment:7 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#14125: Bogus unacceptable type in foreign declaration. -------------------------------------+------------------------------------- Reporter: winter | Owner: (none) Type: bug | Status: patch Priority: high | Milestone: 8.2.2 Component: Compiler (FFI) | Version: 8.2.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Type of failure: GHC rejects | Unknown/Multiple valid program | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Phab:D3865 Wiki Page: | -------------------------------------+------------------------------------- Comment (by RyanGlScott): Gotcha, thanks for confirming. To be on the safe side, I've updated the Diff to include a test that uses `IOErrno UnixReturn` as a return type as well. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/14125#comment:8 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#14125: Bogus unacceptable type in foreign declaration.
-------------------------------------+-------------------------------------
Reporter: winter | Owner: (none)
Type: bug | Status: patch
Priority: high | Milestone: 8.2.2
Component: Compiler (FFI) | Version: 8.2.1
Resolution: | Keywords:
Operating System: Unknown/Multiple | Architecture:
Type of failure: GHC rejects | Unknown/Multiple
valid program | Test Case:
Blocked By: | Blocking:
Related Tickets: | Differential Rev(s): Phab:D3865
Wiki Page: |
-------------------------------------+-------------------------------------
Comment (by Ryan Scott

#14125: Bogus unacceptable type in foreign declaration. -------------------------------------+------------------------------------- Reporter: winter | Owner: (none) Type: bug | Status: merge Priority: high | Milestone: 8.2.2 Component: Compiler (FFI) | Version: 8.2.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: GHC rejects | Test Case: valid program | ffi/should_compile/T14125, | ffi/should_compile/T14125a Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Phab:D3865 Wiki Page: | -------------------------------------+------------------------------------- Changes (by RyanGlScott): * status: patch => merge * testcase: => ffi/should_compile/T14125, ffi/should_compile/T14125a Comment: Given that this bug broke some existing programs, it would be nice to merge this into 8.2.2. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/14125#comment:10 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#14125: Bogus unacceptable type in foreign declaration. -------------------------------------+------------------------------------- Reporter: winter | Owner: (none) Type: bug | Status: merge Priority: high | Milestone: 8.2.2 Component: Compiler (FFI) | Version: 8.2.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: GHC rejects | Test Case: valid program | ffi/should_compile/T14125, | ffi/should_compile/T14125a Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Phab:D3865 Wiki Page: | -------------------------------------+------------------------------------- Comment (by bgamari): Merged with d9e2cf05d5cc79b680a5a75be17263b154a3a53d. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/14125#comment:11 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#14125: Bogus unacceptable type in foreign declaration. -------------------------------------+------------------------------------- Reporter: winter | Owner: (none) Type: bug | Status: closed Priority: high | Milestone: 8.2.2 Component: Compiler (FFI) | Version: 8.2.1 Resolution: fixed | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: GHC rejects | Test Case: valid program | ffi/should_compile/T14125, | ffi/should_compile/T14125a Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Phab:D3865 Wiki Page: | -------------------------------------+------------------------------------- Changes (by bgamari): * status: merge => closed * resolution: => fixed -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/14125#comment:12 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler
participants (1)
-
GHC