Skip to content

Commit 4c15602

Browse files
committed
Separate Swift-to-cdecl parameter lowering from the conversion sequences
Make the operation to convert from cdecl parameter(s) into a Swift parameter a standalone operation, separate from the lowering of Swift parameters to cdecl parameters. They need to be synchronized, but they are not the same.
1 parent 1873da5 commit 4c15602

File tree

5 files changed

+270
-265
lines changed

5 files changed

+270
-265
lines changed
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2025 Apple Inc. and the Swift.org project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of Swift.org project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
extension ConversionStep {
16+
/// Produce a conversion that takes in a value (or set of values) that
17+
/// would be available in a @_cdecl function to represent the given Swift
18+
/// type, and convert that to an instance of the Swift type.
19+
init(cdeclToSwift swiftType: SwiftType) throws {
20+
switch swiftType {
21+
case .function, .optional:
22+
throw LoweringError.unhandledType(swiftType)
23+
24+
case .metatype(let instanceType):
25+
self = .unsafeCastPointer(
26+
.placeholder,
27+
swiftType: instanceType
28+
)
29+
30+
case .nominal(let nominal):
31+
if let knownType = nominal.nominalTypeDecl.knownStandardLibraryType {
32+
// Swift types that map to primitive types in C. These can be passed
33+
// through directly.
34+
if knownType.primitiveCType != nil {
35+
self = .placeholder
36+
return
37+
}
38+
39+
// Typed pointers
40+
if let firstGenericArgument = nominal.genericArguments?.first {
41+
switch knownType {
42+
case .unsafePointer, .unsafeMutablePointer:
43+
self = .typedPointer(
44+
.explodedComponent(.placeholder, component: "pointer"),
45+
swiftType: firstGenericArgument
46+
)
47+
return
48+
49+
case .unsafeBufferPointer, .unsafeMutableBufferPointer:
50+
self = .initialize(
51+
swiftType,
52+
arguments: [
53+
LabeledArgument(
54+
label: "start",
55+
argument: .typedPointer(
56+
.explodedComponent(.placeholder, component: "pointer"),
57+
swiftType: firstGenericArgument)
58+
),
59+
LabeledArgument(
60+
label: "count",
61+
argument: .explodedComponent(.placeholder, component: "count")
62+
)
63+
]
64+
)
65+
return
66+
67+
default:
68+
break
69+
}
70+
}
71+
}
72+
73+
// Arbitrary nominal types.
74+
switch nominal.nominalTypeDecl.kind {
75+
case .actor, .class:
76+
// For actor and class, we pass around the pointer directly.
77+
self = .unsafeCastPointer(.placeholder, swiftType: swiftType)
78+
case .enum, .struct, .protocol:
79+
// For enums, structs, and protocol types, we pass around the
80+
// values indirectly.
81+
self = .passIndirectly(
82+
.pointee(.typedPointer(.placeholder, swiftType: swiftType))
83+
)
84+
}
85+
86+
case .tuple(let elements):
87+
self = .tuplify(try elements.map { try ConversionStep(cdeclToSwift: $0) })
88+
}
89+
}
90+
}

Sources/JExtractSwift/SwiftTypes/SwiftStandardLibraryTypes+CLowering.swift renamed to Sources/JExtractSwift/CDeclLowering/CRepresentation.swift

Lines changed: 45 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,19 @@
1212
//
1313
//===----------------------------------------------------------------------===//
1414

15-
extension SwiftStandardLibraryTypes {
15+
extension CType {
1616
/// Lower the given Swift type down to a its corresponding C type.
1717
///
1818
/// This operation only supports the subset of Swift types that are
1919
/// representable in a Swift `@_cdecl` function. If lowering an arbitrary
2020
/// Swift function, first go through Swift -> cdecl lowering.
21-
func cdeclToCLowering(_ swiftType: SwiftType) throws -> CType {
22-
switch swiftType {
21+
init(cdeclType: SwiftType) throws {
22+
switch cdeclType {
2323
case .nominal(let nominalType):
24-
if let knownType = self[nominalType.nominalTypeDecl] {
25-
return try knownType.loweredCType()
24+
if let knownType = nominalType.nominalTypeDecl.knownStandardLibraryType,
25+
let primitiveCType = knownType.primitiveCType {
26+
self = primitiveCType
27+
return
2628
}
2729

2830
throw CDeclToCLoweringError.invalidNominalType(nominalType.nominalTypeDecl)
@@ -33,29 +35,59 @@ extension SwiftStandardLibraryTypes {
3335
throw CDeclToCLoweringError.invalidFunctionConvention(functionType)
3436

3537
case .c:
36-
let resultType = try cdeclToCLowering(functionType.resultType)
38+
let resultType = try CType(cdeclType: functionType.resultType)
3739
let parameterTypes = try functionType.parameters.map { param in
38-
try cdeclToCLowering(param.type)
40+
try CType(cdeclType: param.type)
3941
}
4042

41-
return .function(
43+
self = .function(
4244
resultType: resultType,
4345
parameters: parameterTypes,
4446
variadic: false
4547
)
4648
}
4749

4850
case .tuple([]):
49-
return .void
51+
self = .void
5052

5153
case .metatype, .optional, .tuple:
52-
throw CDeclToCLoweringError.invalidCDeclType(swiftType)
54+
throw CDeclToCLoweringError.invalidCDeclType(cdeclType)
5355
}
5456
}
5557
}
5658

59+
extension CFunction {
60+
/// Produce a C function that represents the given @_cdecl Swift function.
61+
init(cdeclSignature: SwiftFunctionSignature, cName: String) throws {
62+
assert(cdeclSignature.selfParameter == nil)
63+
64+
let cResultType = try CType(cdeclType: cdeclSignature.result.type)
65+
let cParameters = try cdeclSignature.parameters.map { parameter in
66+
CParameter(
67+
name: parameter.parameterName,
68+
type: try CType(cdeclType: parameter.type).parameterDecay
69+
)
70+
}
71+
72+
self = CFunction(
73+
resultType: cResultType,
74+
name: cName,
75+
parameters: cParameters,
76+
isVariadic: false
77+
)
78+
}
79+
}
80+
81+
enum CDeclToCLoweringError: Error {
82+
case invalidCDeclType(SwiftType)
83+
case invalidNominalType(SwiftNominalTypeDeclaration)
84+
case invalidFunctionConvention(SwiftFunctionType)
85+
}
86+
5787
extension KnownStandardLibraryType {
58-
func loweredCType() throws -> CType {
88+
/// Determine the primitive C type that corresponds to this C standard
89+
/// library type, if there is one.
90+
var primitiveCType: CType? {
5991
switch self {
6092
case .bool: .integral(.bool)
6193
case .int: .integral(.ptrdiff_t)
@@ -74,12 +106,8 @@ extension KnownStandardLibraryType {
74106
case .unsafeRawPointer: .pointer(
75107
.qualified(const: true, volatile: false, type: .void)
76108
)
109+
case .unsafePointer, .unsafeMutablePointer, .unsafeBufferPointer, .unsafeMutableBufferPointer:
110+
nil
77111
}
78112
}
79113
}
80-
enum CDeclToCLoweringError: Error {
81-
case invalidCDeclType(SwiftType)
82-
case invalidNominalType(SwiftNominalTypeDeclaration)
83-
case invalidFunctionConvention(SwiftFunctionType)
84-
}
85-

0 commit comments

Comments
 (0)