[Question] Limitation in 'depth' of multiple KeyPath member lookup

Now I have following property wrapper using dynamic member lookup.

@propertyWrapper
@dynamicMemberLookup
private struct AddSubscript<T, S> {
    var wrappedValue: T

    init(wrappedValue: T, type: S.Type) {
        self.wrappedValue = wrappedValue
    }

    subscript(to type: HashableMetatype<S>) -> Bool {
        get {
            return true
        }
        set {
            //some process
        }
    }

    subscript<U>(dynamicMember keyPath: WritableKeyPath<T, U>) -> U{
        get {
            return wrappedValue[keyPath: keyPath]
        }
        set {
            wrappedValue[keyPath: keyPath] = newValue
        }
    }

}

enum HashableMetatype<T>: Hashable {
    case type(T.Type)

    static func == (lhs: HashableMetatype<T>, rhs: HashableMetatype<T>) -> Bool {
        return true
    }

    func hash(into hasher: inout Hasher) {}
}

HashableMetatype allows me to use the metatype as the key of subscript, but it is not main topic.

I want this property wrapper to work as if it add subscripts, because I thought dynamic member lookup can bring all of added subscripts.

struct Test{
    @AddSubscript(type: Double.self)
    @AddSubscript(type: String.self)
    @AddSubscript(type: Bool.self)
    @AddSubscript(type: Int.self)
    private var value = true

    func test(){
        print(_value[to: .type(Double.self)])   //it should work and it works.
        print(_value[to: .type(String.self)])   //it should work and it works.

        //Cannot convert value of type 'Bool.Type' to expected argument type 'Double.Type'
        print(_value[to: .type(Bool.self)])     //it should work but it doesn't works! 
        //Cannot convert value of type 'Int.Type' to expected argument type 'Double.Type'
        print(_value[to: .type(Int.self)])      //it should work but it doesn't works!

        let keyPath: KeyPath<AddSubscript<Bool, Int>, Bool> = \.[to: .type(Int.self)]
        let keyPath2: KeyPath<AddSubscript<AddSubscript<Bool, Int>, Bool>, Bool> = \.[to: .type(Int.self)]
        let keyPath3: KeyPath<AddSubscript<AddSubscript<Bool, Int>, Bool>, Bool> = \.[to: .type(Bool.self)]
        let keyPath4: KeyPath<AddSubscript<AddSubscript<AddSubscript<Bool, Int>, Bool>, String>, Bool> = \.[to: .type(String.self)]
        let keyPath5: KeyPath<AddSubscript<AddSubscript<AddSubscript<Bool, Int>, Bool>, String>, Bool> = \.[to: .type(Bool.self)]
        //Only this causes error!
        let keyPath6: KeyPath<AddSubscript<AddSubscript<AddSubscript<Bool, Int>, Bool>, String>, Bool> = \.[to: .type(Int.self)]
    }
}

I thought dynamic member lookup can use all keyPaths that KeyPath<T, U> can represent.
Because AddSubscript<AddSubscript<Bool, Int>, Bool> has KeyPath let keyPath2 = \.[to: .type(Int.self)], it is natural that let keyPath6 = \.[to: .type(Int.self)] works.

My question is, what is the expected behavior when wrapped value of @dynamicMemberLookup struct Wrapper<T> has also attribute @dynamicMemberLookup. Is the error is expected? Or, is my understanding wrong...?

[Additional information]

I think it's correct that if the first code works, then the next code should also work.

let value1 = value[dynamicMember: \.xxx]
let value2 = value.xxx

However, it doesn't work when it comes to the code.

struct Test{
    @AddSubscript(type: String.self)
    @AddSubscript(type: Bool.self)
    @AddSubscript(type: Int.self)
    private var value = true

    func test(){
        do{
            //it works.
            let value1 = _value[dynamicMember: \.[to: .type(String.self)]]
            //it works.
            let value2 = _value[to: .type(String.self)]
        }
        do{
            //it works.
            let value1 = _value[dynamicMember: \.[to: .type(Bool.self)]]
            //it doesn't work!
            let value2 = _value[to: .type(Bool.self)]
        }
    }
}

I now suspect it would be a bug of Swift. What do you think?

Terms of Service

Privacy Policy

Cookie Policy