Intellisense Not Showing Public Methods Implemented in an Extension of an Internal Protocol

Consider the case where I have a swift framework with the following code:

    
public protocol PublicProtocol {
    func somePublicMethod()
}

internal protocol InternalProtocol {
    var internalState: Int { get }
}

public class SomeClass: PublicProtocol, InternalProtocol {
    var internalState: Int = 0
    public init() {
    }
}

extension InternalProtocol {
    public func somePublicMethod() {
        print("some public method called", internalState)
    }
}

Now in the app that is using the framework, I can call this code:

    let foo = SomeClass()
    foo.somePublicMethod()

And it compiles just fine. The problem is that somePublicMethod() isn't showing up in intellisense.

A related topic can be found here: Allowing non-public methods to satisfy public protocol requirements

Is the fact that it's not showing up in intellisense an IDE bug, or am I doing something that shouldn't be supported (taking advantage of a bug)?

This seems like a bug to me that this code compiles.

I don't know that we have total consensus on what this code should do, but by the terms of SE-0025, the protocol extension implementation has effective visibility internal, and I do not see how it can satisfy a public requirement of a totally different protocol.

I would conclude that your class does not have an implementation of the public protocol requirement and should not compile.

1 Like

I tried to do something similar to this back in the Swift 3 days, but without the PublicProtocol: [SR-2925] Inconsistent linking in debug vs. release builds w/ public method in extension of internal protocol · Issue #45519 · apple/swift · GitHub. (Long story short, I wanted to expose some types with a bunch of methods with common implementation without exposing the protocol itself.)

Removing the PublicProtocol conformance from SomeClass (which makes it identical to my issue above) confirms this, because then it fails to compile:

error: 'somePublicMethod' is inaccessible due to 'internal' protection level

@Slava_Pestov's comment on my issue was "[t]he conformance should be rejected. The default implementation is not sufficiently visible and thus cannot witness a public protocol requirement," which I assume means the effective visibility like you pointed out. So I would expect the same to apply here, but I guess adding the public conformance with the same-named requirement is letting it slip through?

It looks like there's some "loss" of the original extension context when trying to determine whether these requirements can be satisfied. If I remove the public modifier from the extension method, and have this:

protocol InternalProtocol { ... }

extension InternalProtocol {
    func somePublicMethod() { ... }
}

public class SomeClass: PublicProtocol, InternalProtocol { ... }

Then the compiler errors with this, where the note points to the declaration of somePublicMethod():

error: method 'somePublicMethod()' must be declared public because it matches a requirement in public protocol 'PublicProtocol'
note: mark the instance method as 'public' to satisfy the requirement

If it's true that somePublicMethod() in the extension should not be able to satisfy the requirement, then the diagnostics should not be suggesting that I mark it as public within the same extension. It seems like it shouldn't see it as a viable candidate at all and should tell me that SomeClass doesn't conform to PublicProtocol because it doesn't have a public implementation of somePublicMethod(). But the author also can't add one unless they remove or rename the internal one first, or move the current implementation out of that extension and into a place where it has effective public visibility.