What is the reason why the compiler cannot infer here that Foo<X>(.b) should mean Foo<X>(X.b)?
struct Foo<T> {
public init(_ t: T) { }
public init<P>(_ t: @escaping @Sendable (P) -> T) {}
}
enum X { case a; case b(Int) }
let a1 = Foo<X>(.a)
// COMPILER ERROR: Member 'b' expects argument of type 'Int'
let b1 = Foo<X>(.b)
// Works fine. ...?
let b2 = Foo<X>(X.b)
// Because X.b resolves to this but .b doesn't:
let b3 = Foo<X> { int in X.b(int) }
Or perhaps the question is better phrased as, why should X.b be taken as explicitly communicating that the programmer meant the function { int in X.b(int) } whereas with .b should not?
I'm not sure why simply tacking on X here (when it is clearly already inferred) should change how this statement compiles.
Just curious about the rationale behind this, as usually there is a perfectly good one and I'm just too dense to see it :D
.foo syntax (currently) means "look in the expected type, there should be a static member called foo that produces an instance of that type". In this case, the expected type is (P) -> T, and that doesn't have any members. We'd need an additional rule that says "if the expected type is a function type, look in the function's return type for the member name instead". I don't actually see anything technically wrong with adding such a rule! But it would have to go through the usual language evolution process.
So far the PR seems to work locally, would appreciate any input you might have on the risk factors mentioned in the pitch in light of the implementation. (if you have time of course)