
#9352: Allow `State# s` argument/result types in `ccall` FFI imports -------------------------------------+------------------------------------- Reporter: hvr | Owner: Type: feature | Status: new request | Milestone: 7.10.1 Priority: normal | Version: 7.8.2 Component: Compiler | Keywords: (Type checker) | Architecture: Unknown/Multiple Resolution: | Difficulty: Unknown Operating System: | Blocked By: Unknown/Multiple | Related Tickets: #9281 Type of failure: | None/Unknown | Test Case: | Blocking: | Differential Revisions: | -------------------------------------+------------------------------------- Comment (by simonpj): Simon M: looking into the code, I'm quite perplexed. Have a look at: DsCCall.boxResult. It seems the when we say {{{ foreign import foo :: Int -> Int }}} we actually generate (in effect) an inline use of `unsafePerformIO`. Here's the tidy core: {{{ M.foo :: GHC.Types.Int -> GHC.Types.Int [GblId, Arity=1, Caf=NoCafRefs, Str=DmdType] M.foo = \ (ds_d1A2 :: GHC.Types.Int) -> case ds_d1A2 of _ [Occ=Dead] { GHC.Types.I# ds2_d1A4 -> case {__pkg_ccall main foo Int# -> State# RealWorld -> (# State# RealWorld, Int# #)}_d1A7 ds2_d1A4 GHC.Prim.realWorld# of _ [Occ=Dead] { (# ds3_d1A6, ds4_d1A5 #) -> GHC.Types.I# ds4_d1A5 } } }}} Note that we come up with a `realWorld#` out of thin air and then discard it again... that's the `unsafePerformIO` stuff. Then the code generator has to painstakingly discard all that state-passing nonsense, to get back to a simple C call to "foo". Why do we bother with this? Why not produce this core: {{{ M.foo :: GHC.Types.Int -> GHC.Types.Int M.foo = \ (ds_d1A2 :: GHC.Types.Int) -> case ds_d1A2 of _ [Occ=Dead] { GHC.Types.I# ds2_d1A4 -> case {__pkg_ccall main foo Int# -> Int#}_d1A7 ds2_d1A4 of ds4_d1A5 [Occ=Dead] { DEFAULT -> GHC.Types.I# ds4_d1A5 } } }}} Simpler, more direct, and should generate exactly the same code. At the moment the built-in `FCallId` Ids always have an IO-ish type, but I see no reason to require that. If we did this, then I think the distinction between `boxResult` and `resultWrapper` could disappear, leading to a simpler, compositional structur. Moreover, if we want to accommodate {{{ foreign import foo :: Int -> State# s -> (# State# s, Int #) }}} which doesn't have an IO-ish type (at least not built with the `IO` type constructor), it would seem utterly bizarre to enclose it in the `unsafePerformIO` boilerplate as above. I think Herbert might be able to act on all this, but first let's check that I have not forgotten anything stupid. Simon -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9352#comment:5 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler