SE-0299 Extending Static Member Lookup in Generic Contexts

I pulled this discussion into private with @xedin to reduce noise in the review thread, and I think I now have a much better grasp of the semantics here as well as my discomfort with them! Just going to drop a brief summary here in case anyone else faced the same confusion as myself. :slightly_smiling_face:

@xedin provided a useful example which I think is illustrative:

protocol P {
  static var foo: Foo {
    print("foo via P")
    return Foo()
  }
}

struct Foo : P {
  static var foo: Bar {
    print("foo via Foo")
    return Bar()
  }
}

struct Bar : P {
  var bar: Bar { Bar() }
  var baz: Foo { Foo() }
}

func test<T: P>(_: T) {}

test(.foo.bar.baz)

The main gap in my understanding of the semantics here was not realizing that that the static member lookup on the protocol metatype is only used to determine the base type of the expression—after that is determined, there's a second-pass lookup of the static member on that base type, which may not end up referencing the same declaration.

So in the example above, the expression test(.foo.bar.baz), prints "foo via Foo", since .foo references Foo::foo and has type Bar. The P::foo declaration is only used for finding the Foo type to insert at the implicit base, and does not appear in the type-checked expression.

IMO, having the type inference be influenced by the type of a declaration that doesn't end up in the final expression is pretty unintuitive. So I'm still a -1 on these semantics.

ETA: and of course, @xedin, correct me if it seems like I've misstated anything here.