Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

C types with void explicitly in the parameter list (e.g. void (*)(void)) are assigned the wrong Haskell type #155

Open
lehmacdj opened this issue Feb 5, 2025 · 1 comment · May be fixed by #156

Comments

@lehmacdj
Copy link

lehmacdj commented Feb 5, 2025

When attempting to invoke a function with a void argument like in this snippet:

-- | - (void)prepareForReadingItemsAtURLs:(NSArray<NSURL *> *)readingURLs
--        options:(NSFileCoordinatorReadingOptions)readingOptions
--        writingItemsAtURLs:(NSArray<NSURL *> *)writingURLs
--        options:(NSFileCoordinatorWritingOptions)writingOptions
--        error:(NSError **)outError
--        byAccessor:(void (^)(void (^completionHandler)(void)))batchAccessor;
m_NSFileCoordinator_prepareForReadingAndWritingItems ::
  Ptr NSFileCoordinator ->
  Ptr NSArray ->  -- readingURLs
  NSFileCoordinatorReadingOptions ->
  Ptr NSArray ->  -- writingURLs
  NSFileCoordinatorWritingOptions ->
  Ptr (Ptr NSError) ->
  IO () ->
  IO ()
m_NSFileCoordinator_prepareForReadingAndWritingItems fileCoordinator readingURLs readingOptions writingURLs writingOptions errorPtr accessor = do
  -- let accessor' :: FunPtr (CInt -> IO ()) -> IO () = \completionHandler -> accessor ($(C.peekFunPtr [t| CInt -> IO () |]) completionHandler 0)
  [C.block| void {
    [$(NSFileCoordinator *fileCoordinator)
      prepareForReadingItemsAtURLs: $(NSArray *readingURLs)
      options: $(NSFileCoordinatorReadingOptions readingOptions)
      writingItemsAtURLs: $(NSArray *writingURLs)
      options: $(NSFileCoordinatorWritingOptions writingOptions)
      error: $(NSError **errorPtr)
      byAccessor: ^(void (^completionHandler)(void)) {
        $fun:(void (*accessor)(void))();
        completionHandler()
      }
    ];
  }
  |]

I get an error like so:

• Unacceptable argument type in foreign declaration:
    ‘()’ cannot be marshalled in a foreign call
• When checking declaration:
    foreign import ccall safe "wrapper" inline_c_ffi_6989586621681841573
      :: (() -> IO ()) -> IO (FunPtr (() -> IO ()))

Inspecting the FunPtr docs, I see that this is not the expected type for a function pointer of type void (*)(void) instead it should have type IO () or (). The bug is in buildArr in the antiquoter for $fun:. I'm working on a fix and will make a PR shortly.

@lehmacdj lehmacdj changed the title Handle void arguments correctly C types with void explicitly in the parameter list (e.g. void (*)(void)) are assigned the wrong Haskell type Feb 5, 2025
@lehmacdj lehmacdj linked a pull request Feb 5, 2025 that will close this issue
@lehmacdj
Copy link
Author

lehmacdj commented Feb 5, 2025

As a workaround you can declare the type without a parameter list, e.g. void (*)() for a void (*)(void) function. This is the correct C++ syntax but technically incorrect for C.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant