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

[SR-9902] Function return type metadata generates a no-op in Swift 4.0 #52308

Closed
swift-ci opened this issue Feb 11, 2019 · 6 comments
Closed
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself

Comments

@swift-ci
Copy link
Collaborator

Previous ID SR-9902
Radar None
Original Reporter plinth666 (JIRA User)
Type Bug
Status Resolved
Resolution Invalid
Environment

Swift 4.0 compiler, Xcode 9.2

Additional Detail from JIRA
Votes 0
Component/s Compiler
Labels Bug
Assignee None
Priority Medium

md5: 2754f3f03ba31e7e7564e89fc12b9a62

Issue Description:

Given the following function:

public func NS_PHLivePhotoBadgeOptions () -> PHLivePhotoBadgeOptions.Type ``{

{{ return PHLivePhotoBadgeOptions.self}}

{{}}}

It will compile into a return statement - no code body.

If it is used the calling code will call this function and ignore the result, then call the metadata accessor function.

Although swift code using this works, the problem is that the function violates its contract and can't be called from, say, outside a swift environment.

As a workaround, I'm using this code:

public func NS_PHLivePhotoBadgeOptions (retval: UnsafeMutablePointer<PHLivePhotoBadgeOptions.Type>) ``{

{{ retval.initialize(to: PHLivePhotoBadgeOptions.self, count:1)}}

{{}}}

which at least allows a caller to get the type.

@belkadan
Copy link
Contributor

I believe this is correct (and ABI-contractual) behavior for Swift metatype values: because there is only one possible value of PHLivePhotoBadgeOptions.Type, the representation is empty. You can use Any.Type if you want a general runtime value.

cc @rjmccall, @jckarter

@jckarter
Copy link
Member

Yeah, this is correct behavior. What do you mean by "outside a Swift environment"? Your other example writing to `UnsafeMutablePointer<X.Type>` is also a no-op, because X.Type has only one value so is an empty type. (Nevermind, the Pointer types always point at the maximally abstracted representation, which will give you the metadata pointer value in memory.)

@rjmccall
Copy link
Member

It's okay for a function returning a concrete metatype to understand that the type is trivial and avoid actually doing the work to create the metadata object. The store will work because `UnsafePointer` always stores the most general representation for its type argument, but the more efficient way would be to make the function return a non-concrete type, e.g. by returning `Any.Type`.

@swift-ci
Copy link
Collaborator Author

Comment by Steve Hawley (JIRA)

I disagree. A function declared to return a value needs to return a value. The implementation as is leaves the return register untouched, which means its garbage. Even if there is only one possible value of `PHLivePhotoBadeOptions.Type`, it should return it. I don't see how Any.Type would be a valid substitute for the type metadata for that.

With regards to the work around code, it doesn't look like a no-op to me in the disassembly.

Why do I need this? I'm calling swift code from a C environment and in other code, I need to pass the type metadata back into swift for generic functions (example, construct Swift.Array<T>) as well as to root around in it to get size, stride, etc.

Can you explain in more detail why the singleton nature of type metadata would prevent a function that is declared as returning it from returning it?

@rjmccall
Copy link
Member

You don't actually get to disagree here. You're trying to write C code that matches the Swift ABI, which means you need to do what the Swift ABI does, not what you would find it convenient if the Swift ABI did. If you'd like to work on a compiler feature that makes it easier to match the Swift ABI, e.g. by outputting a C header suitable for use by Clang that declares the public interface of a Swift module in all of its wildly-attributed and name-mangled glory, I think that would be really interesting.

@jckarter
Copy link
Member

Alternatively, if you want Swift functions to be usable from C, use the @_cdecl attribute to export them as C functions, using the C calling convention:

// Swift
@_cdecl("foo") func foo(x: Int) -> Int { ... }

// C
intptr_t foo(intptr_t);

You won't be able to directly use Swift-only types without an analog in C, such as metatypes, but you can control the marshalling to C by converting to types that do exist in C.

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself
Projects
None yet
Development

No branches or pull requests

4 participants