Skip to content

Conversation

Simon-F-AMS
Copy link

@Simon-F-AMS Simon-F-AMS commented Sep 11, 2025

Enhancement: Support Typed Throws

Summary

SpyFactory would use throwableErrorFactory.variableDeclaration(variablePrefix: variablePrefix) to create the throwable error to always be of type (any Error)?.

Main Objective: Support typed throws

Protocol functions with typed throws should result in a throwable error that has the appropriate type in the Spy:

@Spyable
protocol ServiceProtocol {
            func foo(_ added: ((text: String) -> Void)?) throws(ExampleError) -> (() -> Int)?
        }

Should result in a spy:

class ServiceProtocolSpy: ServiceProtocol, @unchecked Sendable {
            init() {
            }
            var fooCallsCount = 0
            var fooCalled: Bool {
                return fooCallsCount > 0
            }
            var fooReceivedAdded: ((text: String) -> Void)?
            var fooReceivedInvocations: [((text: String) -> Void)?] = []
            var fooThrowableError: ExampleError? // Note that this is not (any Error)? anymore
            var fooReturnValue: (() -> Int)?
            var fooClosure: ((((text: String) -> Void)?) throws(ExampleError) -> (() -> Int)?)?
            func foo(_ added: ((text: String) -> Void)?) throws(ExampleError) -> (() -> Int)? {
                fooCallsCount += 1
                fooReceivedAdded = (added)
                fooReceivedInvocations.append((added))
                if let fooThrowableError {
                    throw fooThrowableError // As fooThrowableError now has the correct type, this compiles
                }
                if fooClosure != nil {
                    return try fooClosure!(added)
                } else {
                    return fooReturnValue
                }
            }
        }

Implemented Solution

An additional helper function typedVariableDeclaration(variablePrefix: String, typeSpecifier: String) throws -> VariableDeclSyntax was added to the ThrowableErrorFactory. It distinguishes which function to use by the optional typeSpecifier Parameter that can be passed to variableDeclaration(variablePrefix:, typeSpecifier:)

SpyFactory forwardsfunctionDeclaration.signature.effectSpecifiers?.throwsClause?.type which results in the correct type being set for the error in case the throwing clause is typed

Happy to hear your feedback on this 😊

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant