Skip to content

Commit c537162

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 83b16cf commit c537162

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
@@ -871,44 +871,6 @@ void AttributeChecker::visitSPIAccessControlAttr(SPIAccessControlAttr *attr) {
871871
D->getDescriptiveKind());
872872
}
873873

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

5767-
checker.resolveWitnessViaLookup(valueDecl);
5767+
ResolveWitnessResult result = checker.resolveWitnessViaLookup(valueDecl);
5768+
5769+
if (result == ResolveWitnessResult::Missing &&
5770+
requirement->isSPI()) {
5771+
// SPI requirements need a default value.
5772+
valueDecl->diagnose(diag::spi_attribute_on_protocol_requirement,
5773+
valueDecl->getName());
5774+
}
57685775
}
57695776

57705777
// 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)