Hi,
I have distilled an example of a problem I'm having compiling some generic code that is trying to create a situation where:
- a protocol can only be "conformed-to" by types that also conform to another protocol (using
protocol A where Self: B
) - an extension on protocol A defines a helper function that uses a generic type that is generic over
Self
as mentioned in (1)
The code below is a "working" playground that fails to compile if the Mapped
protocol has a Self
constraint - with a strange compiler error message that the code DefaultBuilder<Self>()
has a Self
that does not conform to the expected types, when the extension it is in clearly has this constraint.
If you remove the Self
constraint on Mapped
the code compiles but of course Mapped can then be used on any type, and I think this has knock-on effects on the verbosity of the implementations of buildMappings
which cannot rely on the compiler knowing that Self is already restricted.
import UIKit
protocol FeatureDefinition: class {
var whatever: String { get }
}
protocol Builder {
associatedtype FeatureType: FeatureDefinition
func add(mapping: String, feature: FeatureType.Type)
}
class DefaultBuilder<FeatureType>: Builder where FeatureType: FeatureDefinition {
func add(mapping: String, feature: FeatureType.Type) {
}
}
/// REMOVE THE CONSTRAINT HERE and it will compile, but not do what is hoped
protocol Mapped where Self: FeatureDefinition {
static func buildMappings<BuilderType>(intents: BuilderType)
where BuilderType: Builder, BuilderType.FeatureType == Self
}
extension Mapped where Self: FeatureDefinition {
static func collectMappings() {
/// This is the problem when the protocol is constrained
let builder = DefaultBuilder<Self>()
Self.buildMappings(intents: builder)
print("Yay!")
}
}
final class TestFeature: FeatureDefinition, Mapped {
var whatever: String { return "Testing" }
static func buildMappings<BuilderType>(intents: BuilderType)
where BuilderType: Builder, BuilderType.FeatureType == TestFeature {
intents.add(mapping: "Some mapping", feature: TestFeature.self)
}
}
TestFeature.collectMappings()