Skip to content

Commit 19621bc

Browse files
committed
Sema: Handle nested compositions and parameterized protocols in diagnoseRetroactiveConformances()
1 parent 13cdf10 commit 19621bc

File tree

2 files changed

+43
-22
lines changed

2 files changed

+43
-22
lines changed

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 30 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1778,6 +1778,33 @@ static TypeRepr *unwrapAttributedRepr(TypeRepr *repr) {
17781778
return repr;
17791779
}
17801780

1781+
static void collectProtocolsFromInheritedEntry(
1782+
const InheritedEntry &entry,
1783+
Type inheritedTy,
1784+
llvm::SmallPtrSetImpl<ProtocolDecl *> &protocolsWithRetroactiveAttr,
1785+
SmallVectorImpl<ProtocolDecl *> &protos) {
1786+
1787+
if (auto *protoTy = inheritedTy->getAs<ProtocolType>()) {
1788+
auto *proto = protoTy->getDecl();
1789+
1790+
// As a fallback, to support previous language versions, also allow
1791+
// this through if the protocol has been explicitly module-qualified.
1792+
TypeRepr *repr = unwrapAttributedRepr(entry.getTypeRepr());
1793+
if (isModuleQualified(repr, proto->getParentModule())) {
1794+
protocolsWithRetroactiveAttr.insert(proto);
1795+
}
1796+
1797+
protos.push_back(proto);
1798+
} else if (auto *pct = inheritedTy->getAs<ProtocolCompositionType>()) {
1799+
for (auto member : pct->getMembers()) {
1800+
collectProtocolsFromInheritedEntry(entry, member,
1801+
protocolsWithRetroactiveAttr, protos);
1802+
}
1803+
} else if (auto *ppt = inheritedTy->getAs<ParameterizedProtocolType>()) {
1804+
protos.push_back(ppt->getProtocol());
1805+
}
1806+
}
1807+
17811808
/// Determines if this extension declares a conformance of a type declared
17821809
/// outside this module to a protocol declared outside this module (but only
17831810
/// in library evolution mode)
@@ -1814,7 +1841,7 @@ static void diagnoseRetroactiveConformances(
18141841
// At this point, we know we're extending a type declared outside this module.
18151842
// We better only be conforming it to protocols declared within this module.
18161843
llvm::SmallMapVector<ProtocolDecl *, bool, 8> protocols;
1817-
llvm::SmallSet<ProtocolDecl *, 8> protocolsWithRetroactiveAttr;
1844+
llvm::SmallPtrSet<ProtocolDecl *, 2> protocolsWithRetroactiveAttr;
18181845

18191846
for (auto *conformance : ext->getLocalConformances()) {
18201847
auto *proto = conformance->getProtocol();
@@ -1842,27 +1869,8 @@ static void diagnoseRetroactiveConformances(
18421869
}
18431870

18441871
SmallVector<ProtocolDecl *, 2> protos;
1845-
if (auto *protoTy = inheritedTy->getAs<ProtocolType>()) {
1846-
auto *proto = protoTy->getDecl();
1847-
1848-
// As a fallback, to support previous language versions, also allow
1849-
// this through if the protocol has been explicitly module-qualified.
1850-
TypeRepr *repr = unwrapAttributedRepr(entry.getTypeRepr());
1851-
if (isModuleQualified(repr, proto->getParentModule())) {
1852-
protocolsWithRetroactiveAttr.insert(proto);
1853-
continue;
1854-
}
1855-
1856-
protos.push_back(proto);
1857-
} else if (auto *compositionTy = inheritedTy->getAs<ProtocolCompositionType>()) {
1858-
for (auto memberTy : compositionTy->getMembers()) {
1859-
if (auto *protoTy = memberTy->getAs<ProtocolType>()) {
1860-
protos.push_back(protoTy->getDecl());
1861-
}
1862-
}
1863-
} else {
1864-
continue;
1865-
}
1872+
collectProtocolsFromInheritedEntry(entry, inheritedTy,
1873+
protocolsWithRetroactiveAttr, protos);
18661874

18671875
for (auto *proto : protos) {
18681876
proto->walkInheritedProtocols([&](ProtocolDecl *decl) {

test/Sema/extension_retroactive_conformances.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ public protocol SampleProtocol2 {}
99
public protocol SampleProtocol1a: SampleProtocol1 {}
1010
public protocol SampleProtocol1b: SampleProtocol1 {}
1111

12+
public protocol SampleProtocol3<A> {
13+
associatedtype A
14+
}
15+
1216
public struct Sample1 {}
1317
public struct Sample2 {}
1418
public struct Sample2a {}
@@ -27,6 +31,9 @@ public struct SampleAlreadyConforms: SampleProtocol1 {}
2731

2832
public struct GenericSample1<T> {}
2933

34+
public struct Sample9 {}
35+
public struct Sample10 {}
36+
3037
#else
3138

3239
import Library
@@ -118,4 +125,10 @@ extension Sample7: SampleProtocol1 & SampleProtocol2 {}
118125

119126
extension Sample8: @retroactive SampleProtocol1 & SampleProtocol2 {} // ok
120127

128+
extension Sample9: SampleProtocol3<Int> {}
129+
// expected-warning@-1 {{extension declares a conformance of imported type 'Sample9' to imported protocol 'SampleProtocol3'; this will not behave correctly if the owners of 'Library' introduce this conformance in the future}}
130+
// expected-note@-2 {{add '@retroactive' to silence this warning}}
131+
132+
extension Sample10: @retroactive SampleProtocol3<Int> {}
133+
121134
#endif

0 commit comments

Comments
 (0)