From 60c711d4a65d3e15356832fba9d27d2579f2d768 Mon Sep 17 00:00:00 2001 From: Allan Shortlidge Date: Sun, 26 Oct 2025 21:22:41 -0700 Subject: [PATCH] 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. --- lib/Sema/TypeCheckDeclPrimary.cpp | 9 ++++----- test/Sema/extension_retroactive_conformances.swift | 12 ++++++++++-- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/lib/Sema/TypeCheckDeclPrimary.cpp b/lib/Sema/TypeCheckDeclPrimary.cpp index 5bb7d285379c1..dc778b70ba234 100644 --- a/lib/Sema/TypeCheckDeclPrimary.cpp +++ b/lib/Sema/TypeCheckDeclPrimary.cpp @@ -1864,6 +1864,7 @@ static void diagnoseRetroactiveConformances( continue; } + bool isMarkedRetroactive = entry.isRetroactive(); SmallVector protos; if (auto *protoTy = inheritedTy->getAs()) { 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()) { @@ -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. diff --git a/test/Sema/extension_retroactive_conformances.swift b/test/Sema/extension_retroactive_conformances.swift index 02d7baf8e7223..fabc0e6bb404e 100644 --- a/test/Sema/extension_retroactive_conformances.swift +++ b/test/Sema/extension_retroactive_conformances.swift @@ -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 {}