5.2 Behavior change with symbol resolution

This code used to work in Xcode 11.3 but fails to compile on Xcode 11.4 beta 3. Would that be expected or no?

// Base class has a struct containing constants
class A {
    struct k {
        static let constantA: Int = 100
    }
}

// Subclass also has a struct containing (different) constants
class B: A {
    struct k {
        static let constantB: Int = 10
    }

    func go(x : Int) -> Int {
        // Reference is resolved and compiles in Xcode 11.3 but not 11.4 beta 3
        return x + k.constantA
    }
}

The error reported is: Type 'B.k' has no member 'constantA'

The new behavior is fine with me but I thought I'd bring it up in case it was unintended.

Looks like [SR-12281] Name resolution of shadowed nested types no longer disambiguates · Issue #54709 · apple/swift · GitHub

Yep, that's the one! Thanks.

1 Like

If I were to change those inner structs to inner classes (containing only static let properties) where B.k: A.k would that incur any practical overhead?

Trying to work around this, I decided it might be best to use the class hierarchy directly instead of trying to build a nested namespace. But it appears that Swift inheritance doesn't work as I'd expect:

    class A {
        static let kConstantA: Int = 100
    }

    class B: A {
        static let kConstantB: Int = 10

        func go(x : Int) -> Int {
            // error: static member 'kConstantA' cannot be used on instance of type 'B'
            return x + kConstantA  // FAIL
        }
    }

Why aren't superclass static properties resolved in subclasses, when the same instance properties would work exactly as expected?

You need to do A.kConstantA here.

I know that, but why? This seems like simple inheritance behavior -- if you can't find the name in the current class, check the superclass.

That’s not the cause of your error. You also cannot use kConstantB there, because static members cannot be used from instance member bodies through unqualified lookup like that, which is what the error message is trying to tell you.

You can, however, write B.kConstantA (or equivalently Self.kConstantA), which will work fine. Or, if you were writing a static method on B, you could use kConstantA directly there.

Ah, got it. Thanks! I always forget that Swift won't resolve static class properties from instance methods without qualification. I don't understand the logic of this design decision but I do remember knowing it at some point.

1 Like