fabi.ionut
(Corut Fabrizio)
1
When creating a protocol that requires inheritance to a class that specialises a generic protocol, the extension implementation is lost outside of the protocol definition.
// Interface
protocol FooType: Hashable, CaseIterable { }
protocol BarType: Hashable { }
protocol Resolver {
associatedtype Foo: FooType
associatedtype Bar: BarType
func bar(for foo: Foo) -> Bar
}
protocol Provider {
associatedtype Foo: FooType
associatedtype Bar: BarType
typealias FooBarMap = [Foo: Bar]
var map: FooBarMap { get }
}
extension Provider {
subscript(_ foo: Foo) -> Bar? {
map[foo]
}
}
// Implementation
enum ActualFoo: FooType, CaseIterable {
case fooOne, fooTwo
}
enum ActualBar: BarType {
case barOne, barTwo
}
class BaseProvider: Provider {
typealias Foo = ActualFoo
typealias Bar = ActualBar
let map: FooBarMap
init(map: FooBarMap) {
self.map = map
}
}
let bp: BaseProvider?
bp?[.fooOne] // works fine, no compiler errors
protocol ExtraProvider: BaseProvider {
var firstBar: Bar? { get }
}
extension ExtraProvider {
func foo() {
self[.fooOne] // works fine, no compiler errors
}
}
var ep: ExtraProvider?
ep?[.fooOne] // Cannot infer contextual base in reference to member 'fooOne'
and the error I get is:
Again, I'm not sure if my assumptions that I make about the generics are correct and this outcome is expected or the compiler is acting a bit funny.
Thank you!
Jumhyn
(Frederick Kellison-Linn)
2
If we fill in the implicit base type with what we expect the compiler to do for us, we get a different error:
ep?[ActualFoo.fooOne] // error: cannot convert value of type 'ActualFoo' to expected argument type 'ExtraProvider.Foo'
It looks like we're not inferring that ExtraProvider.Foo will always be the same type as BaseProvider.Foo. Note that we don't need the optional to reproduce this error, the same issue occurs if ep has static type ExtraProvider.
I believe this works from within ExtraProvider.foo because self has type Self, i.e., the dynamic, concrete conforming type.
I'm not sure if there's a technical reason why we couldn't consider this valid—it seems like we should have enough information in this case to know that ExtraProvider.Foo == ActualFoo for all conforming types, but there might be something I'm missing... 
2 Likes