Skip to content

[jextract] Improve Cdecl lowering #238

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

Merged
merged 1 commit into from
May 31, 2025

Conversation

rintaro
Copy link
Member

@rintaro rintaro commented May 30, 2025

Part of #236 with some test cases.

Cdecl lowering improvements without integrating into the actual workflow.

  • Newly introduce lowerResult() (splitted from lowerParameter() because result lowering can be differnt from parameter lowering.
  • Remove ConversionStep.init(cdeclToSwift:)/.init(swiftToCdecl:). Instead embed the logic in lowerParameter()/lowerResult() so that we can implement type lowering and the actual conversion at the same place.
  • Support 'String', 'Void' and '() -> Void) types
  • Implement getter / setter lowering
  • Fix conversion for tuple returns (see: lowerTupleReturns() test)
  • Reference types are now returned indirectly, as the logic are being unifed. Thanks to this we don't need manual retain() before returning instances, which wasn't implemented correctly.

@rintaro rintaro changed the title [jextract] Improve CDecl lowering [jextract] Improve Cdecl lowering May 30, 2025
@rintaro rintaro requested a review from DougGregor May 30, 2025 21:01
@@ -103,38 +76,30 @@ enum ConversionStep: Equatable {

/// Convert the conversion step into an expression with the given
/// value as the placeholder value in the expression.
func asExprSyntax(isSelf: Bool, placeholder: String) -> ExprSyntax {
func asExprSyntax(placeholder: String, bodyItems: inout [CodeBlockItemSyntax]) -> ExprSyntax? {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using bodyItems, ConversionStep can now introduce side effects, for example it can store the inner step into a variable, then return the DeclReferenceExprSyntax to it.

@rintaro rintaro requested a review from ktoso May 30, 2025 22:48
Copy link
Member

@DougGregor DougGregor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks fantastic, thank you!

Comment on lines +53 to +54
/// providing all of the mappings between the parameter and result types
/// of the original function and its `@_cdecl` counterpart.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Total nit, but there's no parameter or result type for a variable, just the type itself.

Comment on lines +53 to +55
if let generics = node.genericParameterClause {
throw SwiftFunctionTranslationError.generic(generics)
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for making it defensive like this

hasGetter = true
case .keyword(.set), .keyword(._modify), .keyword(.unsafeMutableAddress):
hasSetter = true
default: // Ignore willSet/didSet and unknown accessors.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

willSet/didSet imply that we have both getter and setter, don't they?

switch (hasGetter, hasSetter) {
case (true, true): return [.get, .set]
case (true, false): return [.get]
case (false, true): return [.set]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically, this case is unreachable in well-formed code

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ohh, I didn't know setter only variables are prohibited in Swift 😅

expectedCDecl: """
@_cdecl("c_takeString")
public func c_takeString(_ str: UnsafePointer<Int8>) {
takeString(str: String(cString: str))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very useful, thank you!

Copy link
Collaborator

@ktoso ktoso left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great! Lgtm

* Newly introduce `lowerResult()` (splitted from `lowerParameter()`
  because result lowering can be differnt from parameter lowering.

* Remove `ConversionStep.init(cdeclToSwift:)/.init(swiftToCdecl:)`.
  Instead embed the logic in `lowerParameter()`/`lowerResult()` so that
  we can implement type lowering and the actual conversion at the same
  place.

* Support 'String', 'Void' and '() -> Void) types

* Implement getter / setter lowering

* Fix conversion for tuple returns (see: `lowerTupleReturns()` test)

* Reference types are now returned indirectly, as the logic are being
  unifed. Thanks to this we don't need manual `retain()` before
  returning instances, which wasn't implemented correctly.
@rintaro rintaro force-pushed the jextract-re-lowering branch from 01b8081 to bcd5e0e Compare May 31, 2025 16:03
@rintaro rintaro merged commit c5b9bf3 into swiftlang:main May 31, 2025
12 checks passed
@rintaro rintaro deleted the jextract-re-lowering branch May 31, 2025 16:22
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 this pull request may close these issues.

3 participants