Skip to content

Retain public accessibility for witnesses of external protocol requirements#1139

Open
danwood wants to merge 1 commit into
peripheryapp:masterfrom
danwood:fix-public-protocol-witness
Open

Retain public accessibility for witnesses of external protocol requirements#1139
danwood wants to merge 1 commit into
peripheryapp:masterfrom
danwood:fix-public-protocol-witness

Conversation

@danwood

@danwood danwood commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Symptom

A public member declared in a protocol extension is reported as redundantly public — even when it is the witness for a requirement of an external public protocol such as the standard library's Identifiable. Removing the public modifier, as the report suggests, breaks compilation:

public protocol StatusRepresentable: RawRepresentable, CaseIterable, Identifiable, Hashable, Sendable
    where RawValue == String {}

// `id` is the witness for Identifiable.id (a public protocol requirement).
public extension StatusRepresentable {
    var id: String { rawValue }   // flagged "redundant public"
}

Downgrading the extension from public yields: "property 'id' must be declared public because it matches a requirement in public protocol 'Identifiable'".

Root cause

RedundantExplicitPublicAccessibilityMarker.validateExtension(_:) marks a public extension as redundantly public whenever the extended type is itself flagged redundant. It does not consider that a member of the extension may be the witness for a requirement of an external public protocol, which obliges the witness to remain at least as accessible as the requirement.

The witness relationship survives in the graph as a related reference on the member whose USR does not resolve to any local declaration (because the protocol — e.g. Identifiable — is external). The existing cross-module exemption logic only covers witnesses of local protocols, so external-protocol witnesses fall through.

Fix

Before marking an extension redundantly public, check whether any of its members is the witness for an external protocol requirement: a related reference of a protocol-member-conforming kind, with a matching name, whose USR resolves to no local declaration. If so, the extension is exempt. This is general — it covers any witness for any external public protocol requirement supplied in a protocol-extension default implementation, with no special-casing of Identifiable or id.

Adds an accessibility test covering a public protocol refining Identifiable whose id witness is supplied in a default-implementation extension.

…ements

A public member declared in a protocol extension can be the witness for a
requirement of an external public protocol such as the standard library's
Identifiable. Removing the public modifier from such a witness breaks
compilation, because the witness must be at least as accessible as the
requirement it satisfies.

The redundant public accessibility analysis previously marked the enclosing
extension as redundantly public when the extended type was itself redundant,
without considering that one of the extension's members could be an external
protocol witness. Detect this case by inspecting the member's related
references: a related reference to a protocol member whose USR does not
resolve to a declaration in the source graph indicates the requirement belongs
to an external protocol, which is necessarily public. When such a witness is
present, the extension's public accessibility is retained.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant