Skip to content

Commit 28799e6

Browse files
authored
Merge pull request #32793 from xymus/spi-req-in-spi-proto
[Sema] Only require a default implementation for SPI requirements in non-SPI protocols
2 parents 6ea2034 + d70b0c9 commit 28799e6

File tree

3 files changed

+47
-50
lines changed

3 files changed

+47
-50
lines changed

lib/Sema/TypeCheckAttr.cpp

Lines changed: 0 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -873,44 +873,6 @@ void AttributeChecker::visitSPIAccessControlAttr(SPIAccessControlAttr *attr) {
873873
D->getDescriptiveKind());
874874
}
875875

876-
// If VD is a public protocol requirement it can be SPI only if there's
877-
// a default implementation.
878-
if (auto protocol = dyn_cast<ProtocolDecl>(D->getDeclContext())) {
879-
auto implementations = TypeChecker::lookupMember(
880-
D->getDeclContext(),
881-
protocol->getDeclaredType(),
882-
VD->createNameRef(),
883-
NameLookupFlags::ProtocolMembers);
884-
bool hasDefaultImplementation = llvm::any_of(implementations,
885-
[&](const LookupResultEntry &entry) {
886-
auto entryDecl = entry.getValueDecl();
887-
auto DC = entryDecl->getDeclContext();
888-
auto extension = dyn_cast<ExtensionDecl>(DC);
889-
890-
// The implementation must be defined in the same module in
891-
// an unconstrained extension.
892-
if (!extension ||
893-
extension->getParentModule() != protocol->getParentModule() ||
894-
extension->isConstrainedExtension())
895-
return false;
896-
897-
// For computed properties and subscripts, check that the default
898-
// implementation defines `set` if the protocol declares it.
899-
if (auto protoStorage = dyn_cast<AbstractStorageDecl>(VD))
900-
if (auto entryStorage = dyn_cast<AbstractStorageDecl>(entryDecl))
901-
if (protoStorage->supportsMutation() &&
902-
!entryStorage->supportsMutation())
903-
return false;
904-
905-
return true;
906-
});
907-
908-
if (!hasDefaultImplementation)
909-
diagnoseAndRemoveAttr(attr,
910-
diag::spi_attribute_on_protocol_requirement,
911-
VD->getName());
912-
}
913-
914876
// Forbid stored properties marked SPI in frozen types.
915877
if (auto property = dyn_cast<AbstractStorageDecl>(VD))
916878
if (auto DC = dyn_cast<NominalTypeDecl>(D->getDeclContext()))

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5789,7 +5789,15 @@ void TypeChecker::inferDefaultWitnesses(ProtocolDecl *proto) {
57895789
if (!valueDecl->isProtocolRequirement())
57905790
continue;
57915791

5792-
checker.resolveWitnessViaLookup(valueDecl);
5792+
ResolveWitnessResult result = checker.resolveWitnessViaLookup(valueDecl);
5793+
5794+
if (result == ResolveWitnessResult::Missing &&
5795+
requirement->isSPI() &&
5796+
!proto->isSPI()) {
5797+
// SPI requirements need a default value, unless the protocol is SPI too.
5798+
valueDecl->diagnose(diag::spi_attribute_on_protocol_requirement,
5799+
valueDecl->getName());
5800+
}
57935801
}
57945802

57955803
// Find defaults for any associated conformances rooted on defaulted

test/SPI/protocol_requirement.swift

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,26 @@
11
// Test limitations on SPI protocol requirements.
22

3-
// RUN: %target-typecheck-verify-swift
3+
// RUN: %target-typecheck-verify-swift -enable-library-evolution
44

55
// Reject SPI protocol requirements without a default implementation.
66
public protocol PublicProtoRejected {
7-
@_spi(Private) // expected-error{{protocol requirement 'reqWithoutDefault()' cannot be declared '@_spi' without a default implementation in a protocol extension}}
8-
func reqWithoutDefault()
7+
@_spi(Private)
8+
func reqWithoutDefault() // expected-error{{protocol requirement 'reqWithoutDefault()' cannot be declared '@_spi' without a default implementation in a protocol extension}}
99

10-
@_spi(Private) // expected-error{{protocol requirement 'property' cannot be declared '@_spi' without a default implementation in a protocol extension}}
11-
var property: Int { get set }
10+
@_spi(Private)
11+
func reqWithSharedName(_: Int) // expected-error{{protocol requirement 'reqWithSharedName' cannot be declared '@_spi' without a default implementation in a protocol extension}}
1212

13-
@_spi(Private) // expected-error{{protocol requirement 'propertyWithoutSetter' cannot be declared '@_spi' without a default implementation in a protocol extension}}
14-
var propertyWithoutSetter: Int { get set }
13+
@_spi(Private)
14+
var property: Int { get set } // expected-error{{protocol requirement 'property' cannot be declared '@_spi' without a default implementation in a protocol extension}}
1515

16-
@_spi(Private) // expected-error{{protocol requirement 'subscript(_:)' cannot be declared '@_spi' without a default implementation in a protocol extension}}
17-
subscript(index: Int) -> Int { get set }
16+
@_spi(Private)
17+
var propertyWithoutSetter: Int { get set } // expected-error{{protocol requirement 'propertyWithoutSetter' cannot be declared '@_spi' without a default implementation in a protocol extension}}
1818

19-
@_spi(Private) // expected-error{{protocol requirement 'init()' cannot be declared '@_spi' without a default implementation in a protocol extension}}
20-
init()
19+
@_spi(Private)
20+
subscript(index: Int) -> Int { get set } // expected-error{{protocol requirement 'subscript(_:)' cannot be declared '@_spi' without a default implementation in a protocol extension}}
21+
22+
@_spi(Private)
23+
init() // expected-error{{protocol requirement 'init()' cannot be declared '@_spi' without a default implementation in a protocol extension}}
2124

2225
@_spi(Private) // expected-error{{'@_spi' attribute cannot be applied to this declaration}}
2326
associatedtype T
@@ -26,6 +29,9 @@ public protocol PublicProtoRejected {
2629
extension PublicProtoRejected {
2730
@_spi(Private)
2831
public var propertyWithoutSetter: Int { get { return 42 } }
32+
33+
@_spi(Private)
34+
public func reqWithSharedName(_: String) {}
2935
}
3036

3137
extension PublicProtoRejected where Self : Equatable {
@@ -69,3 +75,24 @@ extension PublicProto {
6975
@_spi(Private)
7076
public init() { }
7177
}
78+
79+
@_spi(Private)
80+
public protocol SPIProtocol {
81+
@_spi(Private)
82+
func reqWithoutDefault()
83+
84+
@_spi(Private)
85+
var property: Int { get set }
86+
87+
@_spi(Private)
88+
var propertyWithoutSetter: Int { get set }
89+
90+
@_spi(Private)
91+
subscript(index: Int) -> Int { get set }
92+
93+
@_spi(Private)
94+
init()
95+
96+
@_spi(Private)
97+
static var staticProperty: Int { get }
98+
}

0 commit comments

Comments
 (0)