Skip to content

Commit de3b85d

Browse files
Merge pull request #128 from nh2/ghcide-foreign-call-stubs
Skip generating foreign calls under ghcide, generate stubs instead
2 parents cc60d93 + f58df41 commit de3b85d

File tree

2 files changed

+38
-13
lines changed

2 files changed

+38
-13
lines changed

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
@@ -70,12 +70,13 @@ import Control.Monad.State (evalStateT, StateT, get, put)
7070
import Control.Monad.Trans.Class (lift)
7171
import Data.Foldable (forM_)
7272
import qualified Data.Map as Map
73-
import Data.Maybe (fromMaybe)
73+
import Data.Maybe (fromMaybe, isJust)
7474
import Data.Traversable (for)
7575
import Data.Typeable (Typeable, cast)
7676
import qualified Language.Haskell.TH as TH
7777
import qualified Language.Haskell.TH.Quote as TH
7878
import qualified Language.Haskell.TH.Syntax as TH
79+
import System.Environment (lookupEnv)
7980
import System.IO.Unsafe (unsafePerformIO, unsafeDupablePerformIO)
8081
import qualified Text.Parsec as Parsec
8182
import qualified Text.Parsec.Pos as Parsec
@@ -319,12 +320,22 @@ inlineCode Code{..} = do
319320
void $ emitVerbatim $ out $ directive ++ codeDefs
320321
-- Create and add the FFI declaration.
321322
ffiImportName <- uniqueFfiImportName
322-
dec <- if codeFunPtr
323-
then
324-
TH.forImpD TH.CCall codeCallSafety ("&" ++ codeFunName) ffiImportName [t| FunPtr $(codeType) |]
325-
else TH.forImpD TH.CCall codeCallSafety codeFunName ffiImportName codeType
326-
TH.addTopDecls [dec]
327-
TH.varE ffiImportName
323+
-- Note [ghcide-support]
324+
-- haskell-language-server / ghcide cannot handle code that use
325+
-- `addForeignFile`/`addForeignSource` as we do here; it will result
326+
-- in linker errors during TH evaluations, see:
327+
-- <https://github.com/haskell/haskell-language-server/issues/365#issuecomment-976294466>
328+
-- Thus for GHCIDE, simply generate a call to `error` instead of a call to a foreign import.
329+
usingGhcide <- TH.runIO $ isJust <$> lookupEnv "__GHCIDE__"
330+
if usingGhcide
331+
then do
332+
[e|error "inline-c: A 'usingGhcide' inlineCode stub was evaluated -- this should not happen" :: $(if codeFunPtr then [t| FunPtr $(codeType) |] else codeType) |]
333+
else do -- Actual foreign function call generation.
334+
dec <- if codeFunPtr
335+
then TH.forImpD TH.CCall codeCallSafety ("&" ++ codeFunName) ffiImportName [t| FunPtr $(codeType) |]
336+
else TH.forImpD TH.CCall codeCallSafety codeFunName ffiImportName codeType
337+
TH.addTopDecls [dec]
338+
TH.varE ffiImportName
328339

329340
uniqueCName :: Maybe String -> TH.Q String
330341
uniqueCName mbPostfix = do

0 commit comments

Comments
 (0)