Thanks @Slava_Pestov and @anthonylatsis — unfortunately this is not a great solution for what I'm trying to achieve.
The issue is then that you protocol extensions cannot use the associated types for some reason. e.g:
extension DismissingUIAction {
public static func perform(context: ActionContext<InputType>, presenter: PresenterType, completion: Completion) -> Completion.Status {
presenter.dismiss(animated: context.input.animated)
return completion.completedSync(.successWithFeatureTermination)
}
}
This function cannot use InputType and PresenterType and these must be changed to explicit types matching the type aliases, which is not the goal. The goal is to say "for types conforming to DismissingUIAction, these associated types must always have this value" because the default implementations rely on this.
In this particular case, I can substitute them — with the risk a conforming type may override the types and break the design contract here (effectively user error). The trouble is that if we ignore the warning, this all behaves "as expected" though perhaps by chance.
However in another situation this does not seem possible:
public protocol IntentAction: IntentBackgroundAction {
/// The type of the `INIntent` thatt this action will implement. This is the Xcode-generated response type produced from your
/// intent definition configuration.
associatedtype IntentType: FlintIntent
/// The type of the `INIntentResponse` for the `INIntent`. This is the Xcode-generated response type produced from your
/// intent definition configuration.
associatedtype IntentResponseType: FlintIntentResponse
/// Automatic aliasing of the presenter to the appropriate type for Intents
typealias PresenterType = IntentResponsePresenter<IntentResponseType>
...
}
In this case if I change the typealias ("a definition") to associatedtype ("a default"), any extensions on this protocol now suffer the same problem but cannot seemingly know the correct types for their function signatures. Here's an example subtype extension:
extension VerifiedActionBinding where ActionType: IntentAction {
public func perform(intent: ActionType.IntentType, completion: @escaping (ActionType.IntentResponseType) -> Void) -> MappedActionResult {
let presenter = IntentResponsePresenter(completion: completion)
return perform(intent: intent, presenter: presenter)
}
public func perform(intent: ActionType.IntentType, presenter: ActionType.PresenterType) -> MappedActionResult {
...
}
Here we get a compiler error Cannot invoke 'perform' with an argument list of type '(intent: ActionType.IntentType, presenter: IntentResponsePresenter<ActionType.IntentResponseType>)' ... and then we end up with this viral unfolding of the type aliases requirement (perform calls another perform variant, which now no longer knows the correct presenter type).
Obviously I have a gap in my understanding here, but this feels like a very weird situation. Using typealias it all works as I would "intuit", and yet I get warnings. Trying to stop the warnings that offer fixits that break the code, I get into a possibly unsolvable situation because the other protocol extensions on the same type cannot be specific to a given PresenterType.
I appreciate this is hard to follow.
Here's the above extension source: https://github.com/MontanaFlossCo/Flint/blob/master/FlintCore/Siri%20Intents%20and%20Shortcuts/VerifiedActionBinding%2BShortcut%2BExtensions.swift
If the above has perform(intent:, presenter:) change to:
func perform(intent: ActionType.IntentType, presenter: IntentResponsePresenter<ActionType.IntentResponseType>)
then the actual protocol type's non-specialised extensions cannot be called by that code:
...and to recap. If I ignore the warning, all is great 