Conform to primary associated type

enum UntypedResult<E: Error> {
    case success, failure(E)
}

protocol InterchangableError<Err> {
    associatedtype Err: Error
}
protocol InterchangableResult<Success, Failure>: InterchangableError where Err == Failure { 
    associatedtype Success
    associatedtype Failure
}

// it works fine.
extension UntypedResult: InterchangableResult where E: Error {
    typealias Success = Void
    typealias Failure = E
    typealias Err = E
}
////////////////////////////////////
extension Optional: InterchangableResult where Wrapped: Error {
    typealias Success = Void
    typealias Failure = Wrapped
    typealias Err = Wrapped
}

// But it requires `Optional` to conform to `InterchangableError`. otherwise, it shows error.
extension Optional: InterchangableError where Wrapped: Error {}

If Optional doesn't conform to InterchangableError, it shows error.

But UntypedResult doesn't require.

Why?

This has nothing to do with primary associated types.

You can conform a type to a protocol either conditionally or unconditionally.

In your example, Optional conforms to InterchangeableResult conditionally. This is because you specified that Optional only conforms to InterchangeableResult if Wrapped conforms to Error.

By contrast, UntypedResult conforms to InterchangeableResult unconditionally. This is because the clause where E: Error is redundant, since you specified in your declaration of UntypedResult that E always has to conform to Error. Therefore, your extension makes it so that UntypedResult always conforms to InterchangeableResult.

When you have multiple protocols in a hierarchy such as P, Q: P, R: Q, and so on, you can write an unconditional conformance of a type to the most specific protocol (for example, R) and Swift will infer unconditional conformance to all the less refined protocols in the hierarchy. In your example, when you conform UntypedResult to InterchangeableResult without conditions, Swift infers the conformance of that type to InterchangeableError without conditions.

However, Swift does not infer conditional conformances. The rationale is explained in SE-0143, the proposal about adding conditional conformances to the language:

Stating a non-conditional conformance to a protocol implicitly states conformances to any of the protocols that the protocol inherits: one can declare conformance to the Collection protocol, and it implies conformance to Sequence as well. However, with conditional conformances, the constraints for the conformance to the inherited protocol may not be clear, and even when there is a clear choice, it will often be incorrect, so the conformance to the inherited protocol will need to be stated explicitly.

In your example, when you conform Optional conditionally to InterchangeableResult, Swift has no information on which to justify a guess that the conditions for conforming to the less refined protocol InterchangeableError are the same as the conditions for conforming to the more refined protocol. You must indicate that this is what you want explicitly.

3 Likes