-
-
Notifications
You must be signed in to change notification settings - Fork 419
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
Allow to override the return type of FFI functions #4060
Conversation
Hi @ergl, The changelog - added label was added to this pull request; all PRs with a changelog label need to have release notes included as part of the PR. If you haven't added release notes already, please do. Release notes are added by creating a uniquely named file in the The basic format of the release notes (using markdown) should be:
Thanks. |
Sweet |
Are there any tutorial updates that need to go along with this? |
@SeanTAllen We should probably add a note about this in the tutorial, although what's currently there is still valid. |
@ergl can you handle the "sounds like it is small" tutorial PR? |
@SeanTAllen Yeah, no problem. |
9412b9e
to
711ae62
Compare
On the sync call for March 1st, we decided to re-add the ability to specify a return type for FFI function calls. This was previously removed by RFC 68 on the grounds that, with FFI declarations being mandatory, specifying a return type would be redundant. Before RFC 68 was implemented, the return type at the call site was not allowed to differ from the return type of the declaration. We have lifted this limitation, which should help users write FFI bindings for C functions that might return different types depending on how they are called. The return type of an FFI function without an explicit return type will default to the return type of its declaration.
711ae62
to
7247ca5
Compare
@SeanTAllen I've reworked the release notes, and added some examples of what this change makes possible. Let me know if you think it's too long/verbose, and I can try to trim it a bit. I'll tackle the tutorial PR tomorrow. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the release notes.
Before merging, I'd like @jemc to sign off on this to verify that it matches his expectation of what we agreed to do for re-enabling this functionality. |
use @ffi_function[I32]() | ||
use @pony_exitcode[None](code: I32) | ||
|
||
actor Main | ||
new create(env: Env) => | ||
let res: (I32 | U8) = @ffi_function[U8]() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This actually needs to be disallowed - the differing return type needs to be ABI-compatible with all other invocations of the same function. Specifically, I think we need to enforce that all of them are the same ABI size.
This is easy for pointers and classes, because they will all be pointer-sized.
But in this case you have a 1-byte and a 4-byte variant, which are not compatible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So that was a bug we had previously with return types for FFI?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, I thought we were preventing this previously with a compiler check, but I could be misremembering.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's an example of where we check ABI compatibility for the param/arg type (in the latest version of the compiler):
ponyc/src/libponyc/codegen/gencall.c
Lines 1124 to 1129 in ca6d725
if((LLVMABISizeOfType(c->target_data, param) != | |
LLVMABISizeOfType(c->target_data, arg_type))) | |
{ | |
report_ffi_type_err(c, decl, ast, name); | |
return NULL; | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
definitely something we need to make sure we have tests for then. and we should update the release notes and tutorial to explain the limitation.
thanks for catching that. it makes sense as a limitation but i wasn't thinking of it when i reviewed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From what I remember, right now we only apply that check across packages to verify that different declarations for the same function are compatible. For FFI calls on a single package, we assumed that the types would always match the local declaration, I think. I'll try to add the check for the return types.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After discussing this with @jemc, we agreed that this check is "good enough" for our purposes, as it will catch multiple calls to the same FFI function with incompatible return types.
It's not feasible to perform the ABI size check against the return type as specified in the FFI declaration without rearchitecting how we perform the code generation for FFI functions in a significant way.
From the point of view of the implementation the compiler will treat the first FFI call to a function as "authoritative", and all future calls to this function will be checked for ABI compatibility against it. This didn't cause a problem before because type checking was making sure that the return type for calls matched the return type of the declaration.
With just a single FFI call happening, there's nothing to check against, and as such the compiler will generate a function with the return type as specified by the call.
I'll add a note to the release notes about the ABI compatiblity. Other than that, I think this is good to merge. |
After introducing #4060, we forgot to re-add the code that ensured that, if a FFI function call specified different return types, those types were being marked as reachable. This created a situation where programs that introduced a new type (for example, a bare lambda) in the context of a FFI return type would crash the compiler. This was due to having missing information about the type during code generation.
After introducing #4060, we forgot to re-add the code that ensured that, if a FFI function call specified different return types, those types were being marked as reachable. This created a situation where programs that introduced a new type (for example, a bare lambda) in the context of a FFI return type would crash the compiler. This was due to having missing information about the type during code generation.
When this is merged, the commit message shoud be the following:
Allow overriding the return type of FFI functions
On the sync call for March 1st, we decided to re-add the ability to specify a
return type for FFI function calls. This was previously removed by RFC 68 on the
grounds that, with FFI declarations being mandatory, specifying a return type
would be redundant.
Before RFC 68 was implemented, the return type at the call site was not allowed
to differ from the return type of the declaration. We have lifted this
limitation, which should help users write FFI bindings for C functions that
might return different types depending on how they are called.
The return type of an FFI function without an explicit return type will default
to the return type of its declaration.