It seems you cannot use implicit self when using dynamic member keypaths. This is a departure from conventional Swift code and appears to be a bug in the compiler. See the error below:
public protocol TestProtocol {
var str1: String { get }
}
@dynamicMemberLookup
open class BaseClass<ProtocolType> {
public let proto: ProtocolType
init(proto: ProtocolType) {
self.proto = proto
}
public subscript<T>(dynamicMember keyPath: KeyPath<ProtocolType, T>) -> T {
return proto[keyPath: keyPath]
}
}
public final class TestClass: BaseClass<TestProtocol> {
func test() {
print(self.proto.str1) // compiles
print(proto.str1) // compiles
print(self.str1) // compiles
print(str1) // ERROR: Use of unresolved identifier 'str1'
}
}
Perhaps the current behavior is desired because it's slightly safer? Otherwise, any symbol will default to dynamic member lookup if not defined in the current scope, which may lead to unexpected runtime failures especially for string-based dynamic member lookup.
Regardless, I think the compiler should produce a fix-it upon undefined symbols when the type of self is @dynamicMemberLookup so that the user knows what's going on.
I don't think there would be any safety implications here, since accessing a random string like self.str12345 fails to compile when it's not defined. That this only has the dynamicMember keyPath implementation means the compiler should understand both self.str1 and str1.