Sema: Fix a regression in retroactive conformance diagnostic suppression.

Module qualifying a protocol name in an inheritance clause should suppress
retroactive conformance diagnostics for the protocol and any protocols it
inherits from, just like adding the `@retroactive` attribute. Fixes a
regression in Swift 6.2 introduced by
https://github.com/swiftlang/swift/pull/81576.

Resolves rdar://162295268 and https://github.com/swiftlang/swift/issues/85153.
This commit is contained in:
Allan Shortlidge
2025-10-26 21:22:41 -07:00
parent 8c1cc1b78a
commit 60c711d4a6
2 changed files with 14 additions and 7 deletions

View File

@@ -1864,6 +1864,7 @@ static void diagnoseRetroactiveConformances(
continue;
}
bool isMarkedRetroactive = entry.isRetroactive();
SmallVector<ProtocolDecl *, 2> protos;
if (auto *protoTy = inheritedTy->getAs<ProtocolType>()) {
auto *proto = protoTy->getDecl();
@@ -1871,10 +1872,8 @@ static void diagnoseRetroactiveConformances(
// 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);
continue;
}
if (isModuleQualified(repr, proto->getParentModule()))
isMarkedRetroactive = true;
protos.push_back(proto);
} else if (auto *compositionTy = inheritedTy->getAs<ProtocolCompositionType>()) {
@@ -1920,7 +1919,7 @@ static void diagnoseRetroactiveConformances(
}
// If it's marked @retroactive, no need to warn.
if (entry.isRetroactive()) {
if (isMarkedRetroactive) {
// Note that we encountered this protocol through a conformance marked
// @retroactive in case multiple clauses cause the protocol to be
// inherited.

View File

@@ -20,8 +20,12 @@ 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 {}
@@ -76,9 +80,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 {}