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