I have a PAT, where I would like to declare a typealias to improve ergonomics of the conforming code.
Below is the simplified example, reproducing the problem:
protocol P {
associatedtype A
typealias B = Array<A>
func make(x: A) -> B
}
struct Q {
typealias A = Int
func make(x: A) -> B { [x] } // error: Use of undeclared type 'B'
}
In actual codebase B is a long generic type that I really don't want to type in every single implementation of the protocol.
My impression was that SE-0092 should allow this, but apparently this does not work.
Indeed . I didn't notice that the error in production code is different from the error in the demo.
The error I'm getting in production is Reference to invalid type alias 'B' of type 'Q'.
After some experimentation, I was able to come up with an example which reproduces the problem:
protocol P {
associatedtype A
typealias B = [A]
associatedtype C
func foo() -> A
func bar(_ x: B) -> C
}
struct Q: P {
func foo() -> Int { 42 }
func bar(_ x: B) -> String { "\(x)" }
}
I'd like compiler to:
infer A based on signature of foo()
resolve B based on this
substitute resolved B into bar()
infer C based on the signature of bar()
In theory, this should be possible - there are no circular dependencies. But apparently, at the moment this is too much.
But if I add explicit type alias for C, inference of A starts to work in the example. While in the production code, C is already declared as a nested type. So, maybe example is still not 100% representative.
Interestingly, for me at least (Swift 5.1.3, Xcode 11.3.1) if I leave both foo and bar in the struct, but comment one out in the protocol, I get different results:
If the protocol has foo as requirement (but not bar), then the program compiles.
But if the protocol has bar as a requirement (but not foo), then it does not compile.
Put another way, the declaration order of foo and bar in the struct affects whether the code compiles.
From what I can tell, the compiler is able to infer that Children has type Q as normal. But once it typechecks foo and bar, it does not know yet whether or not MyWidget comforms to ContainerWidget, and decides the Provider typealias cannot be applied.
My guess is that when one of the function requirements are removed, the compiler is able to make some assumptions since it only needs to satisfy a constraint over a single requirement. But when Provider is referenced twice, the compiler doesn't know how to handle it.