Skip to content

Commit 05b4363

Browse files
authored
Merge pull request #74276 from hborla/6.0-deprecated-default-implementation
[6.0][Sema] Diagnose deprecated default implementations in the witness checker.
2 parents b3c5d28 + 0bfa875 commit 05b4363

File tree

10 files changed

+118
-10
lines changed

10 files changed

+118
-10
lines changed

include/swift/AST/Attr.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2693,6 +2693,10 @@ class DeclAttributes {
26932693
return getUnavailable(ctx) != nullptr;
26942694
}
26952695

2696+
bool isDeprecated(const ASTContext &ctx) const {
2697+
return getDeprecated(ctx) != nullptr;
2698+
}
2699+
26962700
/// Determine whether there is a swiftVersionSpecific attribute that's
26972701
/// unavailable relative to the provided language version.
26982702
bool

include/swift/AST/DiagnosticsSema.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3119,6 +3119,11 @@ ERROR(witness_unavailable,none,
31193119
"unavailable %kind0 was used to satisfy a requirement of protocol %1%select{|: %2}2",
31203120
(const ValueDecl *, Identifier, StringRef))
31213121

3122+
WARNING(witness_deprecated,none,
3123+
"deprecated default implementation is used to satisfy %kind0 required by "
3124+
"protocol %1%select{|: %2}2",
3125+
(const ValueDecl *, Identifier, StringRef))
3126+
31223127
ERROR(redundant_conformance,none,
31233128
"redundant conformance of %0 to protocol %1", (Type, Identifier))
31243129
ERROR(redundant_conformance_conditional,none,

include/swift/AST/RequirementMatch.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,10 @@ enum class CheckKind : unsigned {
239239

240240
/// The witness itself is inaccessible.
241241
WitnessUnavailable,
242+
243+
/// The witness is a deprecated default implementation provided by the
244+
/// protocol.
245+
DefaultWitnessDeprecated,
242246
};
243247
/// Describes the suitability of the chosen witness for
244248
/// the requirement.
@@ -464,4 +468,4 @@ struct RequirementMatch {
464468

465469
}
466470

467-
#endif // SWIFT_AST_REQUIREMENTMATCH_H
471+
#endif // SWIFT_AST_REQUIREMENTMATCH_H

lib/APIDigester/ModuleAnalyzerNodes.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1474,7 +1474,7 @@ SDKNodeInitInfo::SDKNodeInitInfo(SDKContext &Ctx, Decl *D):
14741474
ObjCName(Ctx.getObjcName(D)),
14751475
InitKind(Ctx.getInitKind(D)),
14761476
IsImplicit(D->isImplicit()),
1477-
IsDeprecated(D->getAttrs().getDeprecated(D->getASTContext())),
1477+
IsDeprecated(D->getAttrs().isDeprecated(D->getASTContext())),
14781478
IsABIPlaceholder(isABIPlaceholderRecursive(D)),
14791479
IsFromExtension(isDeclaredInExtension(D)),
14801480
DeclAttrs(collectDeclAttributes(D)) {

lib/IDE/CodeCompletionResultBuilder.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ void CodeCompletionResultBuilder::setAssociatedDecl(const Decl *D) {
212212
CurrentModule = MD;
213213
}
214214

215-
if (D->getAttrs().getDeprecated(D->getASTContext()))
215+
if (D->getAttrs().isDeprecated(D->getASTContext()))
216216
setContextFreeNotRecommended(ContextFreeNotRecommendedReason::Deprecated);
217217
else if (D->getAttrs().getSoftDeprecated(D->getASTContext()))
218218
setContextFreeNotRecommended(

lib/Sema/CSDiagnostics.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4230,7 +4230,7 @@ findImportedCaseWithMatchingSuffix(Type instanceTy, DeclNameRef name) {
42304230

42314231
// Is one more available than the other?
42324232
WORSE(->getAttrs().isUnavailable(ctx));
4233-
WORSE(->getAttrs().getDeprecated(ctx));
4233+
WORSE(->getAttrs().isDeprecated(ctx));
42344234

42354235
// Does one have a shorter name (so the non-matching prefix is shorter)?
42364236
WORSE(->getName().getBaseName().userFacingName().size());

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ computeExportContextBits(ASTContext &Ctx, Decl *D, bool *spi, bool *implicit,
198198
if (D->isImplicit() && !isDeferBody)
199199
*implicit = true;
200200

201-
if (D->getAttrs().getDeprecated(Ctx))
201+
if (D->getAttrs().isDeprecated(Ctx))
202202
*deprecated = true;
203203

204204
if (auto *A = D->getAttrs().getUnavailable(Ctx)) {

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1740,6 +1740,8 @@ checkWitnessAvailability(ValueDecl *requirement,
17401740

17411741
RequirementCheck WitnessChecker::checkWitness(ValueDecl *requirement,
17421742
const RequirementMatch &match) {
1743+
auto &ctx = getASTContext();
1744+
17431745
if (!match.OptionalAdjustments.empty())
17441746
return CheckKind::OptionalityConflict;
17451747

@@ -1769,7 +1771,7 @@ RequirementCheck WitnessChecker::checkWitness(ValueDecl *requirement,
17691771
return RequirementCheck(CheckKind::Availability, requiredAvailability);
17701772
}
17711773

1772-
if (requirement->getAttrs().isUnavailable(getASTContext()) &&
1774+
if (requirement->getAttrs().isUnavailable(ctx) &&
17731775
match.Witness->getDeclContext() == DC) {
17741776
return RequirementCheck(CheckKind::Unavailable);
17751777
}
@@ -1792,11 +1794,11 @@ RequirementCheck WitnessChecker::checkWitness(ValueDecl *requirement,
17921794
}
17931795
}
17941796

1795-
if (match.Witness->getAttrs().isUnavailable(getASTContext()) &&
1796-
!requirement->getAttrs().isUnavailable(getASTContext())) {
1797+
if (match.Witness->getAttrs().isUnavailable(ctx) &&
1798+
!requirement->getAttrs().isUnavailable(ctx)) {
17971799
auto nominalOrExtensionIsUnavailable = [&]() {
17981800
if (auto extension = dyn_cast<ExtensionDecl>(DC)) {
1799-
if (extension->getAttrs().isUnavailable(getASTContext()))
1801+
if (extension->getAttrs().isUnavailable(ctx))
18001802
return true;
18011803
}
18021804

@@ -1813,6 +1815,20 @@ RequirementCheck WitnessChecker::checkWitness(ValueDecl *requirement,
18131815
return CheckKind::WitnessUnavailable;
18141816
}
18151817

1818+
// Warn about deprecated default implementations if the requirement is
1819+
// not deprecated, and the conformance is not deprecated.
1820+
bool isDefaultWitness = false;
1821+
if (auto *nominal = match.Witness->getDeclContext()->getSelfNominalTypeDecl())
1822+
isDefaultWitness = isa<ProtocolDecl>(nominal);
1823+
if (isDefaultWitness &&
1824+
match.Witness->getAttrs().isDeprecated(ctx) &&
1825+
!requirement->getAttrs().isDeprecated(ctx)) {
1826+
auto conformanceContext = ExportContext::forConformance(DC, Proto);
1827+
if (!conformanceContext.isDeprecated()) {
1828+
return RequirementCheck(CheckKind::DefaultWitnessDeprecated);
1829+
}
1830+
}
1831+
18161832
return CheckKind::Success;
18171833
}
18181834

@@ -4374,6 +4390,25 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
43744390
requirement->getName());
43754391
});
43764392
break;
4393+
4394+
case CheckKind::DefaultWitnessDeprecated:
4395+
getASTContext().addDelayedConformanceDiag(
4396+
Conformance, /*isError=*/false,
4397+
[witness, requirement](NormalProtocolConformance *conformance) {
4398+
auto &ctx = witness->getASTContext();
4399+
auto &diags = ctx.Diags;
4400+
SourceLoc diagLoc = getLocForDiagnosingWitness(conformance, witness);
4401+
auto *attr = witness->getAttrs().getDeprecated(ctx);
4402+
EncodedDiagnosticMessage EncodedMessage(attr->Message);
4403+
diags.diagnose(diagLoc, diag::witness_deprecated,
4404+
witness, conformance->getProtocol()->getName(),
4405+
EncodedMessage.Message);
4406+
emitDeclaredHereIfNeeded(diags, diagLoc, witness);
4407+
diags.diagnose(requirement, diag::kind_declname_declared_here,
4408+
DescriptiveDeclKind::Requirement,
4409+
requirement->getName());
4410+
});
4411+
break;
43774412
}
43784413

43794414
if (auto *classDecl = DC->getSelfClassDecl()) {
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// RUN: %target-typecheck-verify-swift
2+
3+
protocol DeprecatedRequirement {
4+
@available(*, deprecated)
5+
func f()
6+
}
7+
8+
extension DeprecatedRequirement {
9+
@available(*, deprecated)
10+
func f() {}
11+
}
12+
13+
// No warning if both the requirement and the default implementation are deprecated
14+
struct S1: DeprecatedRequirement {}
15+
16+
protocol DeprecatedDefault {
17+
func f() // expected-note {{requirement 'f()' declared here}}
18+
}
19+
20+
extension DeprecatedDefault {
21+
@available(*, deprecated)
22+
func f() {} // expected-note {{'f()' declared here}}
23+
}
24+
25+
// expected-warning@+1 {{deprecated default implementation is used to satisfy instance method 'f()' required by protocol 'DeprecatedDefault'}}
26+
struct S2: DeprecatedDefault {}
27+
28+
// No warning if the conformance itself is deprecated
29+
@available(*, deprecated)
30+
struct S3: DeprecatedDefault {
31+
}
32+
33+
struct S4: DeprecatedDefault {
34+
func f() {}
35+
}
36+
37+
struct S5 {}
38+
39+
// No warning if the conformance itself is deprecated
40+
@available(*, deprecated)
41+
extension S5: DeprecatedDefault {}
42+
43+
@available(*, deprecated)
44+
enum UnavailableEnum {
45+
struct Nested: DeprecatedDefault {}
46+
}
47+
48+
// Include message string from @available attribute if provided
49+
protocol DeprecatedDefaultWithMessage {
50+
func f() // expected-note {{requirement 'f()' declared here}}
51+
}
52+
53+
extension DeprecatedDefaultWithMessage {
54+
@available(*, deprecated, message: "write it yourself")
55+
func f() {} // expected-note {{'f()' declared here}}
56+
}
57+
58+
59+
// expected-warning@+1 {{deprecated default implementation is used to satisfy instance method 'f()' required by protocol 'DeprecatedDefaultWithMessage': write it yourself}}
60+
struct S6: DeprecatedDefaultWithMessage {}

tools/SourceKit/lib/SwiftLang/SwiftDocSupport.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -451,7 +451,7 @@ static bool initDocEntityInfo(const Decl *D,
451451
}
452452

453453
Info.IsUnavailable = AvailableAttr::isUnavailable(D);
454-
Info.IsDeprecated = D->getAttrs().getDeprecated(D->getASTContext()) != nullptr;
454+
Info.IsDeprecated = D->getAttrs().isDeprecated(D->getASTContext());
455455
Info.IsOptional = D->getAttrs().hasAttribute<OptionalAttr>();
456456
if (auto *AFD = dyn_cast<AbstractFunctionDecl>(D)) {
457457
Info.IsAsync = AFD->hasAsync();

0 commit comments

Comments
 (0)