Skip to content

Commit ef36f87

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. Resolves SR-8008
1 parent 331e9e8 commit ef36f87

File tree

4 files changed

+91
-5
lines changed

4 files changed

+91
-5
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1834,6 +1834,11 @@ WARNING(redundant_conformance_adhoc_conditional,none,
18341834
NOTE(redundant_conformance_witness_ignored,none,
18351835
"%0 %1 will not be used to satisfy the conformance to %2",
18361836
(DescriptiveDeclKind, DeclName, DeclName))
1837+
WARNING(redundant_conformance_warning,none,
1838+
"redundant conformance of %0 to %1", (Type, Type))
1839+
NOTE(all_types_implicitly_conform_to,none,
1840+
"all types implicitly conform to %0", (Type))
1841+
18371842

18381843
// "Near matches"
18391844
WARNING(req_near_match,none,

lib/Sema/TypeCheckDecl.cpp

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -285,14 +285,17 @@ void TypeChecker::checkInheritanceClause(Decl *decl,
285285
resolver = &defaultResolver;
286286

287287
MutableArrayRef<TypeLoc> inheritedClause;
288+
Type declInterfaceTy;
288289

289290
if (auto type = dyn_cast<TypeDecl>(decl)) {
291+
declInterfaceTy = type->getDeclaredInterfaceType();
290292
inheritedClause = type->getInherited();
291293
} else {
292294
auto ext = cast<ExtensionDecl>(decl);
293295
if (!ext->getExtendedType())
294296
return;
295297

298+
declInterfaceTy = ext->getExtendedType();
296299
inheritedClause = ext->getInherited();
297300

298301
// Protocol extensions cannot have inheritance clauses.
@@ -379,16 +382,37 @@ void TypeChecker::checkInheritanceClause(Decl *decl,
379382
if (inheritedTy->hasError())
380383
continue;
381384

382-
// Check whether we inherited from the same type twice.
383385
CanType inheritedCanTy = inheritedTy->getCanonicalType();
386+
auto isConstraint =
387+
isa<AbstractTypeParamDecl>(decl) || isa<ProtocolDecl>(decl);
388+
389+
// Check for a stated conformance to Any, which is redundant.
390+
// Ignore cases of ': Any' *constraints* that are parsed as inheritance
391+
// clauses, such as with protocol and placeholder decls e.g <T : Any>, as
392+
// these are handled by the generic signature builder along with redundant
393+
// constraints that appear in 'where' clauses.
394+
if (inheritedCanTy == Context.TheAnyType) {
395+
if (!isConstraint) {
396+
auto diagLoc = inherited.getSourceRange().Start;
397+
auto removalRange = getRemovalRange(i);
398+
399+
diagnose(diagLoc, diag::redundant_conformance_warning, declInterfaceTy,
400+
inheritedTy)
401+
.highlight(inherited.getSourceRange())
402+
.fixItRemoveChars(removalRange.Start, removalRange.End);
403+
diagnose(diagLoc, diag::all_types_implicitly_conform_to, inheritedTy);
404+
}
405+
continue;
406+
}
407+
408+
// Check whether we inherited from the same type twice.
384409
auto knownType = inheritedTypes.find(inheritedCanTy);
385410
if (knownType != inheritedTypes.end()) {
386411
// If the duplicated type is 'AnyObject', check whether the first was
387412
// written as 'class'. Downgrade the error to a warning in such cases
388413
// for backward compatibility with Swift <= 4.
389414
if (!Context.LangOpts.isSwiftVersionAtLeast(5) &&
390-
inheritedTy->isAnyObject() &&
391-
(isa<ProtocolDecl>(decl) || isa<AbstractTypeParamDecl>(decl)) &&
415+
inheritedTy->isAnyObject() && isConstraint &&
392416
Lexer::getTokenAtLocation(Context.SourceMgr,
393417
knownType->second.second.Start)
394418
.is(tok::kw_class)) {
@@ -432,8 +456,7 @@ void TypeChecker::checkInheritanceClause(Decl *decl,
432456
//
433457
// Extensions, structs and enums can only inherit from protocol
434458
// compositions that do not contain AnyObject or class members.
435-
if (isa<ProtocolDecl>(decl) ||
436-
isa<AbstractTypeParamDecl>(decl) ||
459+
if (isConstraint ||
437460
(!layout.hasExplicitAnyObject &&
438461
!layout.explicitSuperclass)) {
439462
continue;

test/decl/inherit/inherit.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,15 @@ class D : P, A { } // expected-error{{superclass 'A' must appear first in the in
2121

2222
// SR-8160
2323
class D1 : Any, A { } // expected-error{{superclass 'A' must appear first in the inheritance clause}}{{15-18=}}{{12-12=A, }}
24+
// expected-warning@-1 {{redundant conformance of 'D1' to 'Any'}}
25+
// expected-note@-2 {{all types implicitly conform to 'Any'}}
2426

2527
class D2 : P & P1, A { } // expected-error{{superclass 'A' must appear first in the inheritance clause}}{{18-21=}}{{12-12=A, }}
2628

2729
@usableFromInline
2830
class D3 : Any, A { } // expected-error{{superclass 'A' must appear first in the inheritance clause}}{{15-18=}}{{12-12=A, }}
31+
// expected-warning@-1 {{redundant conformance of 'D3' to 'Any'}}
32+
// expected-note@-2 {{all types implicitly conform to 'Any'}}
2933

3034
@usableFromInline
3135
class D4 : P & P1, A { } // expected-error{{superclass 'A' must appear first in the inheritance clause}}{{18-21=}}{{12-12=A, }}

test/decl/protocol/protocols.swift

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,26 +51,80 @@ 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+
typealias AnyAnyAlias = Any & Any
106+
107+
class X11 : AnyAnyAlias {} // expected-warning {{redundant conformance of 'X11' to 'AnyAnyAlias' (aka 'Any')}} {{10-24=}}
108+
// expected-note@-1 {{all types implicitly conform to 'AnyAnyAlias' (aka 'Any')}}
109+
110+
struct X12 : Any, Any {}
111+
// expected-warning@-1 {{redundant conformance of 'X12' to 'Any'}} {{14-19=}}
112+
// expected-note@-2 {{all types implicitly conform to 'Any'}}
113+
// expected-warning@-3 {{redundant conformance of 'X12' to 'Any'}} {{17-22=}}
114+
// expected-note@-4 {{all types implicitly conform to 'Any'}}
115+
68116
// Explicit conformance checks (unsuccessful)
69117

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

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

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

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

0 commit comments

Comments
 (0)