Skip to content

Commit f4691c0

Browse files
committed
[Sema] Warn about stated conformances to 'Any'
Such a stated conformance is always redundant. This patch purposefully ignores conformance constraints that are parsed as inheritance clauses, such as with protocols and generic placeholders (e.g '<T : Any>'). These are best diagnosed in the generic signature builder.
1 parent 101eea1 commit f4691c0

File tree

3 files changed

+76
-1
lines changed

3 files changed

+76
-1
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1724,6 +1724,11 @@ WARNING(redundant_conformance_adhoc_conditional,none,
17241724
NOTE(redundant_conformance_witness_ignored,none,
17251725
"%0 %1 will not be used to satisfy the conformance to %2",
17261726
(DescriptiveDeclKind, DeclName, DeclName))
1727+
WARNING(redundant_conformance_warning,none,
1728+
"redundant conformance of %0 to %1", (Type, Type))
1729+
NOTE(all_types_implicitly_conform_to,none,
1730+
"all types implicitly conform to %0", (Type))
1731+
17271732

17281733
// "Near matches"
17291734
WARNING(req_near_match,none,

lib/Sema/TypeCheckDecl.cpp

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,12 +325,15 @@ void TypeChecker::checkInheritanceClause(Decl *decl,
325325
resolver = &defaultResolver;
326326

327327
MutableArrayRef<TypeLoc> inheritedClause;
328+
Type declInterfaceTy;
328329

329330
// If we already checked the inheritance clause, don't do so again.
330331
if (auto type = dyn_cast<TypeDecl>(decl)) {
331332
if (type->checkedInheritanceClause())
332333
return;
333334

335+
declInterfaceTy = type->getDeclaredInterfaceType();
336+
334337
// This breaks infinite recursion, which will be diagnosed separately.
335338
type->setCheckedInheritanceClause();
336339
inheritedClause = type->getInherited();
@@ -343,6 +346,8 @@ void TypeChecker::checkInheritanceClause(Decl *decl,
343346
ext->checkedInheritanceClause())
344347
return;
345348

349+
declInterfaceTy = ext->getExtendedType();
350+
346351
// This breaks infinite recursion, which will be diagnosed separately.
347352
ext->setCheckedInheritanceClause();
348353
inheritedClause = ext->getInherited();
@@ -447,8 +452,26 @@ void TypeChecker::checkInheritanceClause(Decl *decl,
447452
if (inheritedTy->hasArchetype() && !isa<GenericTypeParamDecl>(decl))
448453
inheritedTy = inheritedTy->mapTypeOutOfContext();
449454

450-
// Check whether we inherited from the same type twice.
451455
CanType inheritedCanTy = inheritedTy->getCanonicalType();
456+
457+
// Check for a stated conformance to Any, which is redundant.
458+
// Ignore cases of ': Any' *constraints* that are parsed as inheritance
459+
// clauses, such as with protocol and placeholder decls e.g <T : Any>, as
460+
// these should be handled by the generic signature builder along with
461+
// redundant constraints that appear as a part of a 'where' clause.
462+
if (inheritedCanTy == Context.TheAnyType &&
463+
!isa<AbstractTypeParamDecl>(decl) && !isa<ProtocolDecl>(decl)) {
464+
auto diagLoc = inherited.getSourceRange().Start;
465+
auto removalRange = getRemovalRange(i);
466+
467+
diagnose(diagLoc, diag::redundant_conformance_warning, declInterfaceTy,
468+
inheritedTy)
469+
.fixItRemoveChars(removalRange.Start, removalRange.End);
470+
diagnose(diagLoc, diag::all_types_implicitly_conform_to, inheritedTy);
471+
continue;
472+
}
473+
474+
// Check whether we inherited from the same type twice.
452475
auto knownType = inheritedTypes.find(inheritedCanTy);
453476
if (knownType != inheritedTypes.end()) {
454477
// If the duplicated type is 'AnyObject', check whether the first was

test/decl/protocol/protocols.swift

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,26 +51,73 @@ protocol FormattedPrintable : CustomStringConvertible {
5151
func print(format: TestFormat)
5252
}
5353

54+
// expected-warning@+2 {{redundant conformance of 'X0' to 'Any'}} {{13-18=}}
55+
// expected-note@+1 {{all types implicitly conform to 'Any'}}
5456
struct X0 : Any, CustomStringConvertible {
5557
func print() {}
5658
}
5759

60+
// expected-warning@+2 {{redundant conformance of 'X1' to 'Any'}} {{12-17=}}
61+
// expected-note@+1 {{all types implicitly conform to 'Any'}}
5862
class X1 : Any, CustomStringConvertible {
5963
func print() {}
6064
}
6165

66+
// expected-warning@+2 {{redundant conformance of 'X2' to 'Any'}} {{8-14=}}
67+
// expected-note@+1 {{all types implicitly conform to 'Any'}}
6268
enum X2 : Any { }
6369

6470
extension X2 : CustomStringConvertible {
6571
func print() {}
6672
}
6773

74+
struct X5 {
75+
func print() {}
76+
}
77+
extension X5 : Any {} // expected-warning {{redundant conformance of 'X5' to 'Any'}} {{13-19=}}
78+
// expected-note@-1 {{all types implicitly conform to 'Any'}}
79+
80+
extension X5 : Any, CustomStringConvertible {} // expected-warning {{redundant conformance of 'X5' to 'Any'}} {{16-21=}}
81+
// expected-note@-1 {{all types implicitly conform to 'Any'}}
82+
83+
struct X6 {
84+
func print() {}
85+
}
86+
extension X6 : CustomStringConvertible, Any {} // expected-warning {{redundant conformance of 'X6' to 'Any'}} {{39-44=}}
87+
// expected-note@-1 {{all types implicitly conform to 'Any'}}
88+
89+
struct X7<T> : Any {} // expected-warning {{redundant conformance of 'X7<T>' to 'Any'}} {{13-19=}}
90+
// expected-note@-1 {{all types implicitly conform to 'Any'}}
91+
92+
struct X8<T> {
93+
func print() {}
94+
}
95+
extension X8 : Any where T : CustomStringConvertible {} // expected-warning {{redundant conformance of 'X8<T>' to 'Any'}} {{13-19=}}
96+
// expected-note@-1 {{all types implicitly conform to 'Any'}}
97+
98+
typealias AnyAlias = Any
99+
class X9 : AnyAlias {} // expected-warning {{redundant conformance of 'X9' to 'AnyAlias' (aka 'Any')}} {{9-20=}}
100+
// expected-note@-1 {{all types implicitly conform to 'AnyAlias' (aka 'Any')}}
101+
102+
struct X10 : Any & Any {} // expected-warning {{redundant conformance of 'X10' to 'Any'}} {{11-23=}}
103+
// expected-note@-1 {{all types implicitly conform to 'Any'}}
104+
105+
// FIX-ME(SR-8009): Handle these cases.
106+
protocol P5 : Any {}
107+
func foo<T : Any>(_ x: T) {}
108+
68109
// Explicit conformance checks (unsuccessful)
69110

111+
// expected-warning@+2 {{redundant conformance of 'NotPrintableS' to 'Any'}} {{24-29=}}
112+
// expected-note@+1 {{all types implicitly conform to 'Any'}}
70113
struct NotPrintableS : Any, CustomStringConvertible {} // expected-error{{type 'NotPrintableS' does not conform to protocol 'CustomStringConvertible'}}
71114

115+
// expected-warning@+2 {{redundant conformance of 'NotPrintableC' to 'Any'}} {{46-51=}}
116+
// expected-note@+1 {{all types implicitly conform to 'Any'}}
72117
class NotPrintableC : CustomStringConvertible, Any {} // expected-error{{type 'NotPrintableC' does not conform to protocol 'CustomStringConvertible'}}
73118

119+
// expected-warning@+2 {{redundant conformance of 'NotPrintableO' to 'Any'}} {{22-27=}}
120+
// expected-note@+1 {{all types implicitly conform to 'Any'}}
74121
enum NotPrintableO : Any, CustomStringConvertible {} // expected-error{{type 'NotPrintableO' does not conform to protocol 'CustomStringConvertible'}}
75122

76123
struct NotFormattedPrintable : FormattedPrintable { // expected-error{{type 'NotFormattedPrintable' does not conform to protocol 'CustomStringConvertible'}}

0 commit comments

Comments
 (0)