Typed Throws inside Actors crash the compiler

Hello there!

I've been trying to use typed throws feature for a testing (not Swift Testing) framework in our team. However I'm hitting a compiler crash when I'm using actors with generic ErrorType constraint. (With ordinary classes this is not an issue).
With Xcode 16.X I was able to work around the issue, however with the new Xcode 26 betas, it started crashing in runtime.

I have an actor like this:

// defining a typealias doesn't help, but this doesn't prevent the code from compiling in combination with case 3.
public typealias Pipeline<Input, ErrorType: Error, Output> = (Input) throws(ErrorType) -> Output

public actor ThreadSafeMockThrowingTypedErrorFunc<Input, Output, ErrorType: Swift.Error> {

	private var didCall: (Input) throws(ErrorType) -> Void = { _ in }

	public private(set) var invocations: [Input] = []


	// case 1: this doesn't compile
//	 public private(set) var result: Pipeline<Input, ErrorType, Output>

	// case 2: this doesn't compile, but this is the desired version
//	public private(set) var result: (Input) throws(ErrorType) -> Output

//	 case 3: this compiles fine
	public private(set) var result: (Input) throws -> Output

	public var input: Input {
		invocations[invocations.count - 1]
	}

	public var output: Output {
		// if we use case 3, then here we have to `do-catch` in order to satisfy the compiler.
		// the desired version of the code is in MockThrowingTypedErrorFunc.swift
		//	public var output: Output {
		// 		get throws(ErrorType) {
		//			try result(input)
		//		}
		//	}
		get throws(ErrorType) {
			do {
				return try result(input)
			} catch let error as ErrorType { // Swift 6.2 crashes here with `Task XX: EXC_BAD_ACCESS (code=1, address=0x...)` But if I do `po error`, I get `SwiftCompilerActorAndTypedThrowsBugSampleProjectTests.ImageLoadingError.test`
				throw error
			} catch {
				fatalError("There's a bug in the compiler that does not allow us to specify the error type in the signature of the closure (see ``result`` property) when it's used in Actor.")
			}
		}
	}

	public init(function: StaticString = #function, line: Int = #line) {
		result = { _ throws(ErrorType) in
			fatalError("You must provide a result handler before using MockFunc instantiated at line: \(line) of \(function)")
		}
	}

	public func callAndReturn(_ input: Input) throws(ErrorType) -> Output {
		try call(with: input)
		return try output
	}

	public func `throws`(_ error: ErrorType) {
		result = { _ throws(ErrorType) in
			throw error
		}
	}

	private func call(with input: Input) throws(ErrorType) {
		invocations.append(input)
		try didCall(input)
	}
}

And I have a test like this:

@Test("Typed Throw is problematic with actors. It crashes!")
	func threadSafeThrowingMockFuncUnhappyPth() async throws {
		let sut = MockImageLoader()

		await sut.loadAsyncThrowsUrlMock.throws(URLError(.badURL))

		await #expect(throws: URLError(.badURL), performing: { try await sut.loadAsyncThrows(url: URL.sample) })
		#expect(await sut.loadAsyncThrowsUrlMock.input == URL.sample)
	}

I get a crash on this line: } catch let error as ErrorType {
It's persistent with all betas of Xcode 26.

I've put together a sample project here with the full problem:

I wonder if I'm doing something wrong or misusing the API, but the same thing works fine for classes, so I guess there's got to be something about the compiler and actors.

3 Likes

You could try do throws(ErrorType) to avoid needing the catch/fatalError

I wish I could, but the thing is that the only compilable version of the code is var result: (Input) throws -> Output which is the same as throws(any Error). In this case I can't do the do throws(ErrorType) because Thrown expression type 'any Error' cannot be converted to error type 'ErrorType'.
And if the var result: (Input) throws(ErrorType) -> Output compiled in the first place, then I would not need do throws() at all. But it doesn't compile because the compiler crashes :slight_smile: you can find the stacktrace by the attached link to the project :slight_smile:

I believe the compiler crash was addressed by [6.2][IRGen] Set generic context before getting call emission in visitFull… by drexin · Pull Request #83074 · swiftlang/swift · GitHub.

1 Like

Oh! Splendid! I hope Apple will include that in their new beta or at least into the release candidate :smiley:

Ah sorry, missed that.

I've found a few situations where this doesn't compile, complaining that runtime support for typed throws isn't available on the target platform:

let x: (Args) throws(Failure) -> R

But this does:

struct Wrapper<Args, Failure: Error, R> {
    let closure: (Args) throws(Failure) -> R
}

let x: Wrapper<Args, Failure, R>

:woman_shrugging:

Thanks for the suggestion! It actually worked for my case as well!