Unexpected behavior in protocol inheritance
asked 8 hours ago by @qa-fngnovxpqlwkoeikttqq 0 rep · 49 views
I use main actor by default in project settings, and use Swift 6 mode. Here's the code:
public protocol Main {}
nonisolated public protocol NonIso {}
// Foo is on main
// As proven by the compilation failure in `testNonIso()`
public protocol Foo: NonIso, Main {
func foo()
}
nonisolated func testNonIso() {
let f: Foo! = nil
// Call to main actor-isolated instance method 'foo()' in a synchronous nonisolated context
f.foo()
}
As verified by my testNonIso() function, the Foo protocol is isolated to main.
Then I mark Foo as nonisolated, and the error is gone:
public protocol Main {}
nonisolated public protocol NonIso {}
// Foo is on nonisolated
// As proven by no compilation error in `testNonIso()`
nonisolated public protocol Foo: NonIso, Main {
func foo()
}
nonisolated func testNonIso() {
let f: Foo! = nil
// this compiles fine, since Foo is non-isolated
f.foo()
}
The above all makes sense.
Now things will get weird - instead of using NonIso protocol, let's use Codable protocol, which is also non-isolated:
public protocol Main {}
// Now `Foo` becomes non-isolated for some reason. In the previous example Foo was main isolated.
// This is verified by the compilation error when conforming struct `F` to `Foo`
public protocol Foo: Codable, Main {
func foo()
}
// Conformance of 'F' to protocol 'Foo' crosses into main actor-isolated code and can cause data races
struct F: Foo {
func foo() {}
}
The above code gives compilation error, indicating that Foo becomes non-isolated this time.
Now let's mark Foo as @MainActor:
public protocol Main {}
nonisolated public protocol NonIso {}
// Still non-isolated, despite of @MainActor here
@MainActor public protocol Foo: Codable, Main {
func foo()
}
// Conformance of 'F' to protocol 'Foo' crosses into main actor-isolated code and can cause data races
struct F: Foo {
func foo() {}
}
I got exactly the same error, meaning that even if I mark Foo as main actor, it's still non-isolated.
Now just double check and for fun, let's replace Codable back to NonIso in the above code, and the compilation error is gone:
public protocol Main {}
nonisolated public protocol NonIso {}
// Foo is main isolated, with or without @MainActor
@MainActor public protocol Foo: NonIso, Main {
func foo()
}
// Compiles fine this time
struct F: Foo {
func foo() {}
}
I wonder what's the difference between my NonIso protocol vs Codable protocol that results in this behavior?
I am using Xcode 26.2