Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 22 additions & 17 deletions lib/Sema/TypeCheckDeclPrimary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1720,30 +1720,35 @@ static TypeRepr *unwrapAttributedRepr(TypeRepr *repr) {
return repr;
}

struct ProtocolAndRetroactiveStatus {
ProtocolDecl *proto = nullptr;
bool isMarkedRetroactive = false;
};

static void collectProtocolsFromInheritedEntry(
const InheritedEntry &entry,
Type inheritedTy,
llvm::SmallPtrSetImpl<ProtocolDecl *> &protocolsWithRetroactiveAttr,
SmallVectorImpl<ProtocolDecl *> &protos) {
const InheritedEntry &entry, Type inheritedTy,
SmallVectorImpl<ProtocolAndRetroactiveStatus> &protos) {

bool isMarkedRetroactive = entry.isRetroactive();

if (auto *protoTy = inheritedTy->getAs<ProtocolType>()) {
auto *proto = protoTy->getDecl();

// As a fallback, to support previous language versions, also allow
// this through if the protocol has been explicitly module-qualified.
TypeRepr *repr = unwrapAttributedRepr(entry.getTypeRepr());
if (isModuleQualified(repr, proto->getParentModule())) {
protocolsWithRetroactiveAttr.insert(proto);
}
if (isModuleQualified(repr, proto->getParentModule()))
isMarkedRetroactive = true;

protos.push_back(proto);
protos.push_back({proto, isMarkedRetroactive});
} else if (auto *pct = inheritedTy->getAs<ProtocolCompositionType>()) {
for (auto member : pct->getMembers()) {
collectProtocolsFromInheritedEntry(entry, member,
protocolsWithRetroactiveAttr, protos);
// FIXME: Check for module qualification on each composed protocol.
collectProtocolsFromInheritedEntry(entry, member, protos);
}
} else if (auto *ppt = inheritedTy->getAs<ParameterizedProtocolType>()) {
protos.push_back(ppt->getProtocol());
// FIXME: Check for module qualification.
protos.push_back({ppt->getProtocol(), isMarkedRetroactive});
}
}

Expand Down Expand Up @@ -1810,11 +1815,12 @@ static void diagnoseRetroactiveConformances(
continue;
}

SmallVector<ProtocolDecl *, 2> protos;
collectProtocolsFromInheritedEntry(entry, inheritedTy,
protocolsWithRetroactiveAttr, protos);
SmallVector<ProtocolAndRetroactiveStatus, 2> protosAndStatuses;
collectProtocolsFromInheritedEntry(entry, inheritedTy, protosAndStatuses);

for (auto protoAndStatus : protosAndStatuses) {
auto proto = protoAndStatus.proto;

for (auto *proto : protos) {
proto->walkInheritedProtocols([&](ProtocolDecl *decl) {
// If this isn't a retroactive conformance, skip it.
auto found = protocols.find(proto);
Expand Down Expand Up @@ -1846,8 +1852,7 @@ static void diagnoseRetroactiveConformances(
return TypeWalker::Action::Continue;
}

// If it's marked @retroactive, no need to warn.
if (entry.isRetroactive()) {
if (protoAndStatus.isMarkedRetroactive) {
// Note that we encountered this protocol through a conformance marked
// @retroactive in case multiple clauses cause the protocol to be
// inherited.
Expand Down
29 changes: 24 additions & 5 deletions test/Sema/extension_retroactive_conformances.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,20 @@ public struct Sample3 {}
public struct Sample4 {}
public struct Sample5 {}
public struct Sample6 {}
public struct Sample6a {}
public struct Sample6b {}
public struct Sample6c {}
public struct Sample7 {}
public struct Sample8 {}
public struct Sample8a {}

public struct SampleAlreadyConforms: SampleProtocol1 {}

public struct GenericSample1<T> {}

public struct Sample9 {}
public struct Sample10 {}
public struct Sample9a {}
public struct Sample9b {}

#else

Expand Down Expand Up @@ -83,9 +88,13 @@ typealias MySample6 = Sample6
extension MySample6: SampleProtocol1 {} // expected-warning {{extension declares a conformance of imported type 'Sample6' to imported protocol 'SampleProtocol1'}}
// expected-note @-1 {{add '@retroactive' to silence this warning}} {{22-37=@retroactive SampleProtocol1}}

// Ensure module-qualifying both types still silences the warning
// Ensure module-qualifying the protocol silences the warning

extension Library.Sample6: Library.SampleProtocol2 {} // ok, module-qualified.
extension Library.Sample6: Library.SampleProtocol2 {} // ok, both types are module-qualified.
extension Sample6a: Library.SampleProtocol2 {} // ok, protocol is module qualified.
extension Library.Sample6b: SampleProtocol2 {} // expected-warning {{extension declares a conformance of imported type 'Sample6b' to imported protocol 'SampleProtocol2'; this will not behave correctly if the owners of 'Library' introduce this conformance in the future}}
// expected-note @-1 {{add '@retroactive' to silence this warning}}
extension Sample6c: Library.SampleProtocol1a {} // ok, protocol is module qualified.

protocol ClientProtocol {}

Expand Down Expand Up @@ -125,10 +134,20 @@ extension Sample7: SampleProtocol1 & SampleProtocol2 {}

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

// FIXME: Module qualification should suppress this warning
extension Sample8a: Library.SampleProtocol1 & Library.SampleProtocol2 {} // ok
// expected-warning@-1 {{extension declares a conformance of imported type 'Sample8a' to imported protocols 'SampleProtocol1', 'SampleProtocol2'; this will not behave correctly if the owners of 'Library' introduce this conformance in the future}}
// expected-note@-2 {{add '@retroactive' to silence this warning}}

extension Sample9: SampleProtocol3<Int> {}
// 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}}
// expected-note@-2 {{add '@retroactive' to silence this warning}}

extension Sample10: @retroactive SampleProtocol3<Int> {}
extension Sample9a: @retroactive SampleProtocol3<Int> {}

#endif
// FIXME: Module qualification should suppress this warning
extension Sample9b: Library.SampleProtocol3<Int> {}
// expected-warning@-1 {{extension declares a conformance of imported type 'Sample9b' to imported protocol 'SampleProtocol3'; this will not behave correctly if the owners of 'Library' introduce this conformance in the future}}
// expected-note@-2 {{add '@retroactive' to silence this warning}}

#endif