From b0e1b91ed29f272eb8e9aa528eaa2aea2f3fb19c Mon Sep 17 00:00:00 2001 From: Jonathan Grynspan Date: Fri, 20 Jun 2025 17:21:25 -0400 Subject: [PATCH 1/2] Use a consistent definition for unreachable code in macro expansions. This PR defines a single `ExprSyntax` instance we can use for unreachable code paths in macro expansions (where the compiler/swift-syntax requires us to produce an expression but we know we're going to emit an error anyway.) --- Sources/Testing/ExitTests/ExitTest.swift | 2 +- Sources/TestingMacros/ConditionMacro.swift | 6 ++++-- .../TestingMacros/ExitTestCapturedValueMacro.swift | 2 +- .../Additions/FunctionDeclSyntaxAdditions.swift | 12 ++++++++++++ .../Support/ClosureCaptureListParsing.swift | 2 +- Sources/TestingMacros/TagMacro.swift | 2 +- 6 files changed, 20 insertions(+), 6 deletions(-) diff --git a/Sources/Testing/ExitTests/ExitTest.swift b/Sources/Testing/ExitTests/ExitTest.swift index c5579981e..153e6fd28 100644 --- a/Sources/Testing/ExitTests/ExitTest.swift +++ b/Sources/Testing/ExitTests/ExitTest.swift @@ -384,7 +384,7 @@ extension ExitTest { asTypeAt typeAddress: UnsafeRawPointer, withHintAt hintAddress: UnsafeRawPointer? = nil ) -> CBool { - fatalError("Unimplemented") + swt_unreachable() } } diff --git a/Sources/TestingMacros/ConditionMacro.swift b/Sources/TestingMacros/ConditionMacro.swift index 9d0c4f15f..1acde0f86 100644 --- a/Sources/TestingMacros/ConditionMacro.swift +++ b/Sources/TestingMacros/ConditionMacro.swift @@ -13,6 +13,8 @@ public import SwiftSyntax import SwiftSyntaxBuilder public import SwiftSyntaxMacros +private import MachO.dyld + #if !hasFeature(SymbolLinkageMarkers) && SWT_NO_LEGACY_TEST_DISCOVERY #error("Platform-specific misconfiguration: either SymbolLinkageMarkers or legacy test discovery is required to expand #expect(processExitsWith:)") #endif @@ -454,9 +456,9 @@ extension ExitTestConditionMacro { // early if found. guard _diagnoseIssues(with: macro, body: bodyArgumentExpr, in: context) else { if Self.isThrowing { - return #"{ () async throws -> Testing.ExitTest.Result in Swift.fatalError("Unreachable") }()"# + return #"{ () async throws -> Testing.ExitTest.Result in \#(ExprSyntax.unreachable) }()"# } else { - return #"{ () async -> Testing.ExitTest.Result in Swift.fatalError("Unreachable") }()"# + return #"{ () async -> Testing.ExitTest.Result in \#(ExprSyntax.unreachable) }()"# } } diff --git a/Sources/TestingMacros/ExitTestCapturedValueMacro.swift b/Sources/TestingMacros/ExitTestCapturedValueMacro.swift index 4bba47c79..bd346bb3b 100644 --- a/Sources/TestingMacros/ExitTestCapturedValueMacro.swift +++ b/Sources/TestingMacros/ExitTestCapturedValueMacro.swift @@ -50,7 +50,7 @@ public struct ExitTestBadCapturedValueMacro: ExpressionMacro, Sendable { // Diagnose that the type of 'expr' is invalid. context.diagnose(.capturedValueMustBeSendableAndCodable(expr, name: nameExpr)) - return #"Swift.fatalError("Unsupported")"# + return .unreachable } } diff --git a/Sources/TestingMacros/Support/Additions/FunctionDeclSyntaxAdditions.swift b/Sources/TestingMacros/Support/Additions/FunctionDeclSyntaxAdditions.swift index 9b9378283..090cb2375 100644 --- a/Sources/TestingMacros/Support/Additions/FunctionDeclSyntaxAdditions.swift +++ b/Sources/TestingMacros/Support/Additions/FunctionDeclSyntaxAdditions.swift @@ -178,3 +178,15 @@ extension FunctionParameterSyntax { return baseType.trimmedDescription } } + +// MARK: - + +extension ExprSyntax { + /// An expression representing an unreachable code path. + /// + /// Use this expression when a macro will emit an error diagnostic but the + /// compiler still requires us to produce a valid expression. + static var unreachable: Self { + #"Swift.fatalError("Unreachable")"# + } +} diff --git a/Sources/TestingMacros/Support/ClosureCaptureListParsing.swift b/Sources/TestingMacros/Support/ClosureCaptureListParsing.swift index 08536aa69..c4266c99f 100644 --- a/Sources/TestingMacros/Support/ClosureCaptureListParsing.swift +++ b/Sources/TestingMacros/Support/ClosureCaptureListParsing.swift @@ -41,7 +41,7 @@ struct CapturedValueInfo { init(_ capture: ClosureCaptureSyntax, in context: some MacroExpansionContext) { self.capture = capture - self.expression = #"Swift.fatalError("Unsupported")"# + self.expression = .unreachable self.type = "Swift.Never" // We don't support capture specifiers at this time. diff --git a/Sources/TestingMacros/TagMacro.swift b/Sources/TestingMacros/TagMacro.swift index 624f812cd..01932ef5d 100644 --- a/Sources/TestingMacros/TagMacro.swift +++ b/Sources/TestingMacros/TagMacro.swift @@ -22,7 +22,7 @@ public struct TagMacro: PeerMacro, AccessorMacro, Sendable { /// This property is used rather than simply returning the empty array in /// order to suppress a compiler diagnostic about not producing any accessors. private static var _fallbackAccessorDecls: [AccessorDeclSyntax] { - [#"get { Swift.fatalError("Unreachable") }"#] + [#"get { \#(ExprSyntax.unreachable) }"#] } public static func expansion( From c74617366d9f94384562ba09ac0250e0437085b6 Mon Sep 17 00:00:00 2001 From: Jonathan Grynspan Date: Mon, 23 Jun 2025 10:01:39 -0400 Subject: [PATCH 2/2] Remove stray import --- Sources/TestingMacros/ConditionMacro.swift | 2 -- 1 file changed, 2 deletions(-) diff --git a/Sources/TestingMacros/ConditionMacro.swift b/Sources/TestingMacros/ConditionMacro.swift index 1acde0f86..c176c96b5 100644 --- a/Sources/TestingMacros/ConditionMacro.swift +++ b/Sources/TestingMacros/ConditionMacro.swift @@ -13,8 +13,6 @@ public import SwiftSyntax import SwiftSyntaxBuilder public import SwiftSyntaxMacros -private import MachO.dyld - #if !hasFeature(SymbolLinkageMarkers) && SWT_NO_LEGACY_TEST_DISCOVERY #error("Platform-specific misconfiguration: either SymbolLinkageMarkers or legacy test discovery is required to expand #expect(processExitsWith:)") #endif