Skip to content

Commit f58df41

Browse files
committed
Skip generating foreign calls under ghcide, generate stubs instead
1 parent 1e9be42 commit f58df41

2 files changed

Lines changed: 38 additions & 13 deletions

File tree

inline-c/src/Language/C/Inline/FunPtr.hs

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ module Language.C.Inline.FunPtr
99
, uniqueFfiImportName
1010
) where
1111

12+
import Data.Maybe (isJust)
1213
import Foreign.Ptr (FunPtr)
14+
import System.Environment (lookupEnv)
1315
import qualified Language.Haskell.TH as TH
1416
import qualified Language.Haskell.TH.Syntax as TH
1517

@@ -27,9 +29,15 @@ import qualified Language.Haskell.TH.Syntax as TH
2729
mkFunPtr :: TH.TypeQ -> TH.ExpQ
2830
mkFunPtr hsTy = do
2931
ffiImportName <- uniqueFfiImportName
30-
dec <- TH.forImpD TH.CCall TH.Safe "wrapper" ffiImportName [t| $(hsTy) -> IO (FunPtr $(hsTy)) |]
31-
TH.addTopDecls [dec]
32-
TH.varE ffiImportName
32+
-- See note [ghcide-support]
33+
usingGhcide <- TH.runIO $ isJust <$> lookupEnv "__GHCIDE__"
34+
if usingGhcide
35+
then do
36+
[e|error "inline-c: A 'usingGhcide' mkFunPtr stub was evaluated -- this should not happen" :: $(hsTy) -> IO (FunPtr $(hsTy)) |]
37+
else do -- Actual foreign function call generation.
38+
dec <- TH.forImpD TH.CCall TH.Safe "wrapper" ffiImportName [t| $(hsTy) -> IO (FunPtr $(hsTy)) |]
39+
TH.addTopDecls [dec]
40+
TH.varE ffiImportName
3341

3442
-- | @$('mkFunPtrFromName' 'foo)@, if @foo :: 'CDouble' -> 'IO'
3543
-- 'CDouble'@, splices in an expression of type @'IO' ('FunPtr'
@@ -56,9 +64,15 @@ mkFunPtrFromName name = do
5664
peekFunPtr :: TH.TypeQ -> TH.ExpQ
5765
peekFunPtr hsTy = do
5866
ffiImportName <- uniqueFfiImportName
59-
dec <- TH.forImpD TH.CCall TH.Safe "dynamic" ffiImportName [t| FunPtr $(hsTy) -> $(hsTy) |]
60-
TH.addTopDecls [dec]
61-
TH.varE ffiImportName
67+
usingGhcide <- TH.runIO $ isJust <$> lookupEnv "__GHCIDE__"
68+
-- See note [ghcide-support]
69+
if usingGhcide
70+
then do
71+
[e|error "inline-c: A 'usingGhcide' peekFunPtr stub was evaluated -- this should not happen" :: FunPtr $(hsTy) -> $(hsTy) |]
72+
else do -- Actual foreign function call generation.
73+
dec <- TH.forImpD TH.CCall TH.Safe "dynamic" ffiImportName [t| FunPtr $(hsTy) -> $(hsTy) |]
74+
TH.addTopDecls [dec]
75+
TH.varE ffiImportName
6276

6377
-- TODO absurdly, I need to 'newName' twice for things to work. I found
6478
-- this hack in language-c-inline. Why is this?

inline-c/src/Language/C/Inline/Internal.hs

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,13 @@ import Control.Monad.State (evalStateT, StateT, get, put)
6464
import Control.Monad.Trans.Class (lift)
6565
import Data.Foldable (forM_)
6666
import qualified Data.Map as Map
67-
import Data.Maybe (fromMaybe)
67+
import Data.Maybe (fromMaybe, isJust)
6868
import Data.Traversable (for)
6969
import Data.Typeable (Typeable, cast)
7070
import qualified Language.Haskell.TH as TH
7171
import qualified Language.Haskell.TH.Quote as TH
7272
import qualified Language.Haskell.TH.Syntax as TH
73+
import System.Environment (lookupEnv)
7374
import System.IO.Unsafe (unsafePerformIO, unsafeDupablePerformIO)
7475
import qualified Text.Parsec as Parsec
7576
import qualified Text.Parsec.Pos as Parsec
@@ -298,12 +299,22 @@ inlineCode Code{..} = do
298299
void $ emitVerbatim $ out $ directive ++ codeDefs
299300
-- Create and add the FFI declaration.
300301
ffiImportName <- uniqueFfiImportName
301-
dec <- if codeFunPtr
302-
then
303-
TH.forImpD TH.CCall codeCallSafety ("&" ++ codeFunName) ffiImportName [t| FunPtr $(codeType) |]
304-
else TH.forImpD TH.CCall codeCallSafety codeFunName ffiImportName codeType
305-
TH.addTopDecls [dec]
306-
TH.varE ffiImportName
302+
-- Note [ghcide-support]
303+
-- haskell-language-server / ghcide cannot handle code that use
304+
-- `addForeignFile`/`addForeignSource` as we do here; it will result
305+
-- in linker errors during TH evaluations, see:
306+
-- <https://github.com/haskell/haskell-language-server/issues/365#issuecomment-976294466>
307+
-- Thus for GHCIDE, simply generate a call to `error` instead of a call to a foreign import.
308+
usingGhcide <- TH.runIO $ isJust <$> lookupEnv "__GHCIDE__"
309+
if usingGhcide
310+
then do
311+
[e|error "inline-c: A 'usingGhcide' inlineCode stub was evaluated -- this should not happen" :: $(if codeFunPtr then [t| FunPtr $(codeType) |] else codeType) |]
312+
else do -- Actual foreign function call generation.
313+
dec <- if codeFunPtr
314+
then TH.forImpD TH.CCall codeCallSafety ("&" ++ codeFunName) ffiImportName [t| FunPtr $(codeType) |]
315+
else TH.forImpD TH.CCall codeCallSafety codeFunName ffiImportName codeType
316+
TH.addTopDecls [dec]
317+
TH.varE ffiImportName
307318

308319
uniqueCName :: Maybe String -> TH.Q String
309320
uniqueCName mbPostfix = do

0 commit comments

Comments
 (0)