Skip to content

Commit 5be252a

Browse files
committed
[Sema] Move the check for SPI protocol requirements to existing logic
Asides from removing duplicated code this change also now checks implicit SPI requirements and applies only in library evolution mode.
1 parent f88fd50 commit 5be252a

File tree

3 files changed

+19
-50
lines changed

3 files changed

+19
-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: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5755,7 +5755,14 @@ void TypeChecker::inferDefaultWitnesses(ProtocolDecl *proto) {
57555755
if (!valueDecl->isProtocolRequirement())
57565756
continue;
57575757

5758-
checker.resolveWitnessViaLookup(valueDecl);
5758+
ResolveWitnessResult result = checker.resolveWitnessViaLookup(valueDecl);
5759+
5760+
if (result == ResolveWitnessResult::Missing &&
5761+
requirement->isSPI()) {
5762+
// SPI requirements need a default value.
5763+
valueDecl->diagnose(diag::spi_attribute_on_protocol_requirement,
5764+
valueDecl->getName());
5765+
}
57595766
}
57605767

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

test/SPI/protocol_requirement.swift

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
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+
var property: Int { get set } // expected-error{{protocol requirement 'property' 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 propertyWithoutSetter: Int { get set } // expected-error{{protocol requirement 'propertyWithoutSetter' 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+
subscript(index: Int) -> Int { get set } // expected-error{{protocol requirement 'subscript(_:)' 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+
init() // expected-error{{protocol requirement 'init()' cannot be declared '@_spi' without a default implementation in a protocol extension}}
2121

2222
@_spi(Private) // expected-error{{'@_spi' attribute cannot be applied to this declaration}}
2323
associatedtype T

0 commit comments

Comments
 (0)