@@ -618,6 +618,48 @@ extension CustomTypeWrapperMacro: AccessorMacro {
618618 }
619619}
620620
621+ public struct UnwrapMacro : CodeItemMacro {
622+ public static func expansion(
623+ of node: some FreestandingMacroExpansionSyntax ,
624+ in context: some MacroExpansionContext
625+ ) throws -> [ CodeBlockItemSyntax ] {
626+ guard !node. argumentList. isEmpty else {
627+ throw CustomError . message ( " '#UnwrapMacro' requires arguments " )
628+ }
629+ let errorThrower = node. trailingClosure
630+ let identifiers = try node. argumentList. map { argument in
631+ guard let tupleElement = argument. as ( TupleExprElementSyntax . self) ,
632+ let identifierExpr = tupleElement. expression. as ( IdentifierExprSyntax . self) else {
633+ throw CustomError . message ( " Arguments must be identifiers " )
634+ }
635+ return identifierExpr. identifier
636+ }
637+
638+ func elseBlock( _ token: TokenSyntax ) -> CodeBlockSyntax {
639+ let expr : ExprSyntax
640+ if let errorThrower {
641+ expr = """
642+ \( errorThrower) ( " \( raw: token. text) " )
643+ """
644+ } else {
645+ expr = """
646+ fatalError( " ' \( raw: token. text) ' is nil " )
647+ """
648+ }
649+ return . init( statements: . init( [ . init(
650+ leadingTrivia: " " , item: . expr( expr) , trailingTrivia: " " ) ] ) )
651+ }
652+
653+ return identifiers. map { identifier in
654+ CodeBlockItemSyntax ( item: CodeBlockItemSyntax . Item. stmt (
655+ """
656+
657+ guard let \( raw: identifier. text) else \( elseBlock ( identifier) )
658+ """ ) )
659+ }
660+ }
661+ }
662+
621663// MARK: Assertion helper functions
622664
623665/// Assert that expanding the given macros in the original source produces
@@ -685,6 +727,7 @@ public let testMacros: [String: Macro.Type] = [
685727 " wrapAllProperties " : WrapAllProperties . self,
686728 " wrapStoredProperties " : WrapStoredProperties . self,
687729 " customTypeWrapper " : CustomTypeWrapperMacro . self,
730+ " unwrap " : UnwrapMacro . self
688731]
689732
690733final class MacroSystemTests : XCTestCase {
@@ -976,4 +1019,36 @@ final class MacroSystemTests: XCTestCase {
9761019 )
9771020
9781021 }
1022+
1023+ func testUnwrap( ) {
1024+ AssertMacroExpansion (
1025+ macros: testMacros,
1026+ """
1027+ let x: Int? = 1
1028+ let y: Int? = nil
1029+ let z: Int? = 3
1030+ #unwrap(x, y, z)
1031+ #unwrap(x, y, z) {
1032+ fatalError( " nil is \\ ($0) " )
1033+ }
1034+ """ ,
1035+ """
1036+ let x: Int? = 1
1037+ let y: Int? = nil
1038+ let z: Int? = 3
1039+ guard let x else { fatalError( " 'x' is nil " ) }
1040+ guard let y else { fatalError( " 'y' is nil " ) }
1041+ guard let z else { fatalError( " 'z' is nil " ) }
1042+ guard let x else { {
1043+ fatalError( " nil is \\ ($0) " )
1044+ }( " x " ) }
1045+ guard let y else { {
1046+ fatalError( " nil is \\ ($0) " )
1047+ }( " y " ) }
1048+ guard let z else { {
1049+ fatalError( " nil is \\ ($0) " )
1050+ }( " z " ) }
1051+ """
1052+ )
1053+ }
9791054}
0 commit comments