@@ -1247,11 +1247,10 @@ func parseCxxSpansInSignature(
12471247}
12481248
12491249func parseMacroParam(
1250- _ paramAST : LabeledExprSyntax , _ signature: FunctionSignatureSyntax , _ rewriter: CountExprRewriter ,
1250+ _ paramExpr : ExprSyntax , _ signature: FunctionSignatureSyntax , _ rewriter: CountExprRewriter ,
12511251 nonescapingPointers: inout Set < Int > ,
12521252 lifetimeDependencies: inout [ SwiftifyExpr : [ LifetimeDependence ] ]
12531253) throws -> ParamInfo ? {
1254- let paramExpr = paramAST. expression
12551254 guard let enumConstructorExpr = paramExpr. as ( FunctionCallExprSyntax . self) else {
12561255 throw DiagnosticError (
12571256 " expected _SwiftifyInfo enum literal as argument, got ' \( paramExpr) ' " , node: paramExpr)
@@ -1577,6 +1576,121 @@ func deconstructFunction(_ declaration: some DeclSyntaxProtocol) throws -> Funct
15771576 throw DiagnosticError ( " @_SwiftifyImport only works on functions and initializers " , node: declaration)
15781577}
15791578
1579+ func constructOverloadFunction( forDecl declaration: some DeclSyntaxProtocol , leadingTrivia: Trivia ,
1580+ args arguments: [ ExprSyntax ] , spanAvailability: String ? ,
1581+ typeMappings: [ String : String ] ? ) throws -> DeclSyntax {
1582+ let origFuncComponents = try deconstructFunction ( declaration)
1583+ let ( funcComponents, rewriter) = renameParameterNamesIfNeeded ( origFuncComponents)
1584+
1585+ var nonescapingPointers = Set < Int > ( )
1586+ var lifetimeDependencies : [ SwiftifyExpr : [ LifetimeDependence ] ] = [ : ]
1587+ var parsedArgs = try arguments. compactMap {
1588+ try parseMacroParam (
1589+ $0, funcComponents. signature, rewriter, nonescapingPointers: & nonescapingPointers,
1590+ lifetimeDependencies: & lifetimeDependencies)
1591+ }
1592+ parsedArgs. append (
1593+ contentsOf: try parseCxxSpansInSignature ( funcComponents. signature, typeMappings) )
1594+ setNonescapingPointers ( & parsedArgs, nonescapingPointers)
1595+ setLifetimeDependencies ( & parsedArgs, lifetimeDependencies)
1596+ // We only transform non-escaping spans.
1597+ parsedArgs = parsedArgs. filter {
1598+ if let cxxSpanArg = $0 as? CxxSpan {
1599+ return cxxSpanArg. nonescaping || cxxSpanArg. pointerIndex == . return
1600+ } else {
1601+ return true
1602+ }
1603+ }
1604+ try checkArgs ( parsedArgs, funcComponents)
1605+ parsedArgs. sort { a, b in
1606+ // make sure return value cast to Span happens last so that withUnsafeBufferPointer
1607+ // doesn't return a ~Escapable type
1608+ if a. pointerIndex != . return && b. pointerIndex == . return {
1609+ return true
1610+ }
1611+ if a. pointerIndex == . return && b. pointerIndex != . return {
1612+ return false
1613+ }
1614+ return paramOrReturnIndex ( a. pointerIndex) < paramOrReturnIndex ( b. pointerIndex)
1615+ }
1616+ let baseBuilder = FunctionCallBuilder ( funcComponents)
1617+
1618+ let builder : BoundsCheckedThunkBuilder = parsedArgs. reduce (
1619+ baseBuilder,
1620+ { ( prev, parsedArg) in
1621+ parsedArg. getBoundsCheckedThunkBuilder ( prev, funcComponents)
1622+ } )
1623+ let newSignature = try builder. buildFunctionSignature ( [ : ] , nil )
1624+ var eliminatedArgs = Set < Int > ( )
1625+ let basicChecks = try builder. buildBasicBoundsChecks ( & eliminatedArgs)
1626+ let compoundChecks = try builder. buildCompoundBoundsChecks ( )
1627+ let checks = ( basicChecks + compoundChecks) . map { e in
1628+ CodeBlockItemSyntax ( leadingTrivia: " \n " , item: e)
1629+ }
1630+ let call : CodeBlockItemSyntax =
1631+ if declaration. is ( InitializerDeclSyntax . self) {
1632+ CodeBlockItemSyntax (
1633+ item: CodeBlockItemSyntax . Item (
1634+ try builder. buildFunctionCall ( [ : ] ) ) )
1635+ } else {
1636+ CodeBlockItemSyntax (
1637+ item: CodeBlockItemSyntax . Item (
1638+ ReturnStmtSyntax (
1639+ returnKeyword: . keyword( . return, trailingTrivia: " " ) ,
1640+ expression: try builder. buildFunctionCall ( [ : ] ) ) ) )
1641+ }
1642+ let body = CodeBlockSyntax ( statements: CodeBlockItemListSyntax ( checks + [ call] ) )
1643+ let returnLifetimeAttribute = getReturnLifetimeAttribute ( funcComponents, lifetimeDependencies)
1644+ let lifetimeAttrs =
1645+ returnLifetimeAttribute + paramLifetimeAttributes( newSignature, funcComponents. attributes)
1646+ let availabilityAttr = try getAvailability ( newSignature, spanAvailability)
1647+ let disfavoredOverload : [ AttributeListSyntax . Element ] =
1648+ [
1649+ . attribute(
1650+ AttributeSyntax (
1651+ atSign: . atSignToken( ) ,
1652+ attributeName: IdentifierTypeSyntax ( name: " _disfavoredOverload " ) ) )
1653+ ]
1654+ let attributes =
1655+ funcComponents. attributes. filter { e in
1656+ switch e {
1657+ case . attribute( let attr) :
1658+ // don't apply this macro recursively, and avoid dupe _alwaysEmitIntoClient
1659+ let name = attr. attributeName. as ( IdentifierTypeSyntax . self) ? . name. text
1660+ return name == nil || ( name != " _SwiftifyImport " && name != " _alwaysEmitIntoClient " )
1661+ default : return true
1662+ }
1663+ } + [
1664+ . attribute(
1665+ AttributeSyntax (
1666+ atSign: . atSignToken( ) ,
1667+ attributeName: IdentifierTypeSyntax ( name: " _alwaysEmitIntoClient " ) ) )
1668+ ]
1669+ + availabilityAttr
1670+ + lifetimeAttrs
1671+ + disfavoredOverload
1672+ let trivia =
1673+ leadingTrivia + . docLineComment( " /// This is an auto-generated wrapper for safer interop \n " )
1674+ if let origFuncDecl = declaration. as ( FunctionDeclSyntax . self) {
1675+ return DeclSyntax (
1676+ origFuncDecl
1677+ . with ( \. signature, newSignature)
1678+ . with ( \. body, body)
1679+ . with ( \. attributes, AttributeListSyntax ( attributes) )
1680+ . with ( \. leadingTrivia, trivia) )
1681+ }
1682+ if let origInitDecl = declaration. as ( InitializerDeclSyntax . self) {
1683+ return DeclSyntax (
1684+ origInitDecl
1685+ . with ( \. signature, newSignature)
1686+ . with ( \. body, body)
1687+ . with ( \. attributes, AttributeListSyntax ( attributes) )
1688+ . with ( \. leadingTrivia, trivia) )
1689+ }
1690+ throw DiagnosticError (
1691+ " Expected function decl or initializer decl, found: \( declaration. kind) " , node: declaration)
1692+ }
1693+
15801694/// A macro that adds safe(r) wrappers for functions with unsafe pointer types.
15811695/// Depends on bounds, escapability and lifetime information for each pointer.
15821696/// Intended to map to C attributes like __counted_by, __ended_by and __no_escape,
@@ -1590,9 +1704,6 @@ public struct SwiftifyImportMacro: PeerMacro {
15901704 in context: some MacroExpansionContext
15911705 ) throws -> [ DeclSyntax ] {
15921706 do {
1593- let origFuncComponents = try deconstructFunction ( declaration)
1594- let ( funcComponents, rewriter) = renameParameterNamesIfNeeded ( origFuncComponents)
1595-
15961707 let argumentList = node. arguments!. as ( LabeledExprListSyntax . self) !
15971708 var arguments = [ LabeledExprSyntax] ( argumentList)
15981709 let typeMappings = try parseTypeMappingParam ( arguments. last)
@@ -1603,107 +1714,12 @@ public struct SwiftifyImportMacro: PeerMacro {
16031714 if spanAvailability != nil {
16041715 arguments = arguments. dropLast ( )
16051716 }
1606- var nonescapingPointers = Set < Int > ( )
1607- var lifetimeDependencies : [ SwiftifyExpr : [ LifetimeDependence ] ] = [ : ]
1608- var parsedArgs = try arguments. compactMap {
1609- try parseMacroParam (
1610- $0, funcComponents. signature, rewriter, nonescapingPointers: & nonescapingPointers,
1611- lifetimeDependencies: & lifetimeDependencies)
1612- }
1613- parsedArgs. append ( contentsOf: try parseCxxSpansInSignature ( funcComponents. signature, typeMappings) )
1614- setNonescapingPointers ( & parsedArgs, nonescapingPointers)
1615- setLifetimeDependencies ( & parsedArgs, lifetimeDependencies)
1616- // We only transform non-escaping spans.
1617- parsedArgs = parsedArgs. filter {
1618- if let cxxSpanArg = $0 as? CxxSpan {
1619- return cxxSpanArg. nonescaping || cxxSpanArg. pointerIndex == . return
1620- } else {
1621- return true
1622- }
1623- }
1624- try checkArgs ( parsedArgs, funcComponents)
1625- parsedArgs. sort { a, b in
1626- // make sure return value cast to Span happens last so that withUnsafeBufferPointer
1627- // doesn't return a ~Escapable type
1628- if a. pointerIndex != . return && b. pointerIndex == . return {
1629- return true
1630- }
1631- if a. pointerIndex == . return && b. pointerIndex != . return {
1632- return false
1633- }
1634- return paramOrReturnIndex ( a. pointerIndex) < paramOrReturnIndex ( b. pointerIndex)
1635- }
1636- let baseBuilder = FunctionCallBuilder ( funcComponents)
1637-
1638- let builder : BoundsCheckedThunkBuilder = parsedArgs. reduce (
1639- baseBuilder,
1640- { ( prev, parsedArg) in
1641- parsedArg. getBoundsCheckedThunkBuilder ( prev, funcComponents)
1642- } )
1643- let newSignature = try builder. buildFunctionSignature ( [ : ] , nil )
1644- var eliminatedArgs = Set < Int > ( )
1645- let basicChecks = try builder. buildBasicBoundsChecks ( & eliminatedArgs)
1646- let compoundChecks = try builder. buildCompoundBoundsChecks ( )
1647- let checks = ( basicChecks + compoundChecks) . map { e in
1648- CodeBlockItemSyntax ( leadingTrivia: " \n " , item: e)
1649- }
1650- var call : CodeBlockItemSyntax
1651- if declaration. is ( InitializerDeclSyntax . self) {
1652- call = CodeBlockItemSyntax (
1653- item: CodeBlockItemSyntax . Item (
1654- try builder. buildFunctionCall ( [ : ] ) ) )
1655- } else {
1656- call = CodeBlockItemSyntax (
1657- item: CodeBlockItemSyntax . Item (
1658- ReturnStmtSyntax (
1659- returnKeyword: . keyword( . return, trailingTrivia: " " ) ,
1660- expression: try builder. buildFunctionCall ( [ : ] ) ) ) )
1661- }
1662- let body = CodeBlockSyntax ( statements: CodeBlockItemListSyntax ( checks + [ call] ) )
1663- let returnLifetimeAttribute = getReturnLifetimeAttribute ( funcComponents, lifetimeDependencies)
1664- let lifetimeAttrs =
1665- returnLifetimeAttribute + paramLifetimeAttributes( newSignature, funcComponents. attributes)
1666- let availabilityAttr = try getAvailability ( newSignature, spanAvailability)
1667- let disfavoredOverload : [ AttributeListSyntax . Element ] =
1668- [
1669- . attribute(
1670- AttributeSyntax (
1671- atSign: . atSignToken( ) ,
1672- attributeName: IdentifierTypeSyntax ( name: " _disfavoredOverload " ) ) )
1673- ]
1674- let attributes = funcComponents. attributes. filter { e in
1675- switch e {
1676- case . attribute( let attr) :
1677- // don't apply this macro recursively, and avoid dupe _alwaysEmitIntoClient
1678- let name = attr. attributeName. as ( IdentifierTypeSyntax . self) ? . name. text
1679- return name == nil || ( name != " _SwiftifyImport " && name != " _alwaysEmitIntoClient " )
1680- default : return true
1681- }
1682- } + [
1683- . attribute(
1684- AttributeSyntax (
1685- atSign: . atSignToken( ) ,
1686- attributeName: IdentifierTypeSyntax ( name: " _alwaysEmitIntoClient " ) ) )
1687- ]
1688- + availabilityAttr
1689- + lifetimeAttrs
1690- + disfavoredOverload
1691- let trivia = node. leadingTrivia + . docLineComment( " /// This is an auto-generated wrapper for safer interop \n " )
1692- if let origFuncDecl = declaration. as ( FunctionDeclSyntax . self) {
1693- return [ DeclSyntax ( origFuncDecl
1694- . with ( \. signature, newSignature)
1695- . with ( \. body, body)
1696- . with ( \. attributes, AttributeListSyntax ( attributes) )
1697- . with ( \. leadingTrivia, trivia) ) ]
1698- }
1699- if let origInitDecl = declaration. as ( InitializerDeclSyntax . self) {
1700- return [ DeclSyntax ( origInitDecl
1701- . with ( \. signature, newSignature)
1702- . with ( \. body, body)
1703- . with ( \. attributes, AttributeListSyntax ( attributes) )
1704- . with ( \. leadingTrivia, trivia) ) ]
1705- }
1706- return [ ]
1717+ let args = arguments. map { $0. expression }
1718+ return [
1719+ try constructOverloadFunction (
1720+ forDecl: declaration, leadingTrivia: node. leadingTrivia, args: args,
1721+ spanAvailability: spanAvailability,
1722+ typeMappings: typeMappings) ]
17071723 } catch let error as DiagnosticError {
17081724 context. diagnose (
17091725 Diagnostic (
0 commit comments