Skip to content

Commit b871528

Browse files
authored
Merge pull request swiftlang#32524 from OnyekachiSamuel/fix-confusing-protocol-diagnostic
[Diagnostics] Fix Confusing Protocol Diagnostic
2 parents d87e7c8 + a08f421 commit b871528

19 files changed

+83
-32
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1801,11 +1801,11 @@ ERROR(type_cannot_conform_to_nsobject,none,
18011801

18021802
ERROR(use_of_equal_instead_of_equality,none,
18031803
"use of '=' in a boolean context, did you mean '=='?", ())
1804-
18051804
ERROR(type_cannot_conform, none,
1806-
"%select{|value of protocol }0type %1 cannot conform to %2; "
1807-
"only struct/enum/class types can conform to protocols",
1808-
(bool, Type, Type))
1805+
"%select{type %1|protocol %1 as a type}0 cannot conform to "
1806+
"%select{%3|the protocol itself}2; "
1807+
"only concrete types such as structs, enums and classes can conform to protocols",
1808+
(bool, Type, bool, Type))
18091809
NOTE(required_by_opaque_return,none,
18101810
"required by opaque return type of %0 %1", (DescriptiveDeclKind, DeclName))
18111811
NOTE(required_by_decl,none,

include/swift/AST/EducationalNotes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,5 +65,6 @@ EDUCATIONAL_NOTES(append_interpolation_static,
6565
"string-interpolation-conformance.md")
6666
EDUCATIONAL_NOTES(append_interpolation_void_or_discardable,
6767
"string-interpolation-conformance.md")
68+
EDUCATIONAL_NOTES(type_cannot_conform, "protocol-type-non-conformance.md")
6869

6970
#undef EDUCATIONAL_NOTES

lib/Sema/CSDiagnostics.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -500,7 +500,9 @@ bool MissingConformanceFailure::diagnoseTypeCannotConform(
500500
}
501501

502502
emitDiagnostic(diag::type_cannot_conform,
503-
nonConformingType->isExistentialType(), nonConformingType,
503+
nonConformingType->isExistentialType(),
504+
nonConformingType,
505+
nonConformingType->isEqual(protocolType),
504506
protocolType);
505507

506508
if (auto *OTD = dyn_cast<OpaqueTypeDecl>(AffectedDecl)) {
@@ -2087,7 +2089,8 @@ bool ContextualFailure::diagnoseAsError() {
20872089
if (CTP == CTP_ForEachStmt) {
20882090
if (fromType->isAnyExistentialType()) {
20892091
emitDiagnostic(diag::type_cannot_conform,
2090-
/*isExistentialType=*/true, fromType, toType);
2092+
/*isExistentialType=*/true, fromType,
2093+
fromType->isEqual(toType), toType);
20912094
return true;
20922095
}
20932096

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4312,7 +4312,8 @@ void swift::diagnoseConformanceFailure(Type T,
43124312

43134313
if (!T->isObjCExistentialType()) {
43144314
diags.diagnose(ComplainLoc, diag::type_cannot_conform, true,
4315-
T, Proto->getDeclaredType());
4315+
T, T->isEqual(Proto->getDeclaredType()),
4316+
Proto->getDeclaredType());
43164317
return;
43174318
}
43184319

test/Constraints/diagnostics.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,9 @@ f0(i, i, // expected-error@:7 {{cannot convert value of type 'Int' to expected a
5151

5252

5353
// Cannot conform to protocols.
54-
f5(f4) // expected-error {{type '(Int) -> Int' cannot conform to 'P2'; only struct/enum/class types can conform to protocols}}
55-
f5((1, "hello")) // expected-error {{type '(Int, String)' cannot conform to 'P2'; only struct/enum/class types can conform to protocols}}
56-
f5(Int.self) // expected-error {{type 'Int.Type' cannot conform to 'P2'; only struct/enum/class types can conform to protocols}}
54+
f5(f4) // expected-error {{type '(Int) -> Int' cannot conform to 'P2'; only concrete types such as structs, enums and classes can conform to protocols}}
55+
f5((1, "hello")) // expected-error {{type '(Int, String)' cannot conform to 'P2'; only concrete types such as structs, enums and classes can conform to protocols}}
56+
f5(Int.self) // expected-error {{type 'Int.Type' cannot conform to 'P2'; only concrete types such as structs, enums and classes can conform to protocols}}
5757

5858
// Tuple element not convertible.
5959
f0(i,
@@ -104,7 +104,7 @@ func f8<T:P2>(_ n: T, _ f: @escaping (T) -> T) {} // expected-note {{where 'T'
104104
f8(3, f4) // expected-error {{global function 'f8' requires that 'Int' conform to 'P2'}}
105105
typealias Tup = (Int, Double)
106106
func f9(_ x: Tup) -> Tup { return x }
107-
f8((1,2.0), f9) // expected-error {{type 'Tup' (aka '(Int, Double)') cannot conform to 'P2'; only struct/enum/class types can conform to protocols}}
107+
f8((1,2.0), f9) // expected-error {{type 'Tup' (aka '(Int, Double)') cannot conform to 'P2'; only concrete types such as structs, enums and classes can conform to protocols}}
108108

109109
// <rdar://problem/19658691> QoI: Incorrect diagnostic for calling nonexistent members on literals
110110
1.doesntExist(0) // expected-error {{value of type 'Int' has no member 'doesntExist'}}

test/Constraints/function_builder_diags.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ struct Label<L> : P where L : P { // expected-note 2 {{'L' declared as parameter
179179
}
180180

181181
func test_51167632() -> some P {
182-
AnyP(G { // expected-error {{type 'Label<_>.Type' cannot conform to 'P'; only struct/enum/class types can conform to protocols}}
182+
AnyP(G { // expected-error {{type 'Label<_>.Type' cannot conform to 'P'; only concrete types such as structs, enums and classes can conform to protocols}}
183183
Text("hello")
184184
Label // expected-error {{generic parameter 'L' could not be inferred}}
185185
// expected-note@-1 {{explicitly specify the generic arguments to fix this issue}} {{10-10=<<#L: P#>>}}

test/Constraints/generics.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ func r22459135() {
188188

189189
// <rdar://problem/19710848> QoI: Friendlier error message for "[] as Set"
190190
// <rdar://problem/22326930> QoI: "argument for generic parameter 'Element' could not be inferred" lacks context
191-
_ = [] as Set // expected-error {{value of protocol type 'Any' cannot conform to 'Hashable'; only struct/enum/class types can conform to protocols}}
191+
_ = [] as Set // expected-error {{protocol 'Any' as a type cannot conform to 'Hashable'; only concrete types such as structs, enums and classes can conform to protocols}}
192192
// expected-note@-1 {{required by generic struct 'Set' where 'Element' = 'Any'}}
193193

194194

test/Generics/conditional_conformances_literals.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,9 +128,9 @@ func combined() {
128128

129129
// Needs self conforming protocols:
130130
let _: Conforms = [[0: [1 : [works]] as Conforms]]
131-
// expected-error@-1 {{value of protocol type 'Conforms' cannot conform to 'Conforms'; only struct/enum/class types can conform to protocols}}
131+
// expected-error@-1 {{protocol 'Conforms' as a type cannot conform to the protocol itself; only concrete types such as structs, enums and classes can conform to protocols}}
132132

133133
let _: Conforms = [[0: [1 : [fails]] as Conforms]]
134134
// expected-error@-1 {{protocol 'Conforms' requires that 'Fails' conform to 'Conforms'}}
135-
// expected-error@-2 {{value of protocol type 'Conforms' cannot conform to 'Conforms'; only struct/enum/class types can conform to protocols}}
135+
// expected-error@-2 {{protocol 'Conforms' as a type cannot conform to the protocol itself; only concrete types such as structs, enums and classes can conform to protocols}}
136136
}

test/Generics/existential_restrictions.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ func fAOE(_ t: AnyObject) { }
2323
func fT<T>(_ t: T) { }
2424

2525
func testPassExistential(_ p: P, op: OP, opp: OP & P, cp: CP, sp: SP, any: Any, ao: AnyObject) {
26-
fP(p) // expected-error{{value of protocol type 'P' cannot conform to 'P'; only struct/enum/class types can conform to protocols}}
26+
fP(p) // expected-error{{protocol 'P' as a type cannot conform to the protocol itself; only concrete types such as structs, enums and classes can conform to protocols}}
2727
fAO(p) // expected-error{{global function 'fAO' requires that 'P' be a class type}}
2828
fAOE(p) // expected-error{{argument type 'P' expected to be an instance of a class or class-constrained type}}
2929
fT(p)
@@ -37,8 +37,8 @@ func testPassExistential(_ p: P, op: OP, opp: OP & P, cp: CP, sp: SP, any: Any,
3737
fAOE(cp)
3838
fT(cp)
3939

40-
fP(opp) // expected-error{{value of protocol type 'OP & P' cannot conform to 'P'; only struct/enum/class types can conform to protocols}}
41-
fOP(opp) // expected-error{{value of protocol type 'OP & P' cannot conform to 'OP'; only struct/enum/class types can conform to protocols}}
40+
fP(opp) // expected-error{{protocol 'OP & P' as a type cannot conform to 'P'; only concrete types such as structs, enums and classes can conform to protocols}}
41+
fOP(opp) // expected-error{{protocol 'OP & P' as a type cannot conform to 'OP'; only concrete types such as structs, enums and classes can conform to protocols}}
4242
fAO(opp) // expected-error{{global function 'fAO' requires that 'OP & P' be a class type}}
4343
fAOE(opp)
4444
fT(opp)
@@ -64,9 +64,9 @@ class GAO<T : AnyObject> {} // expected-note 2{{requirement specified as 'T' : '
6464
func blackHole(_ t: Any) {}
6565

6666
func testBindExistential() {
67-
blackHole(GP<P>()) // expected-error{{value of protocol type 'P' cannot conform to 'P'; only struct/enum/class types can conform to protocols}}
67+
blackHole(GP<P>()) // expected-error{{protocol 'P' as a type cannot conform to the protocol itself; only concrete types such as structs, enums and classes can conform to protocols}}
6868
blackHole(GOP<OP>())
69-
blackHole(GCP<CP>()) // expected-error{{value of protocol type 'CP' cannot conform to 'CP'; only struct/enum/class types can conform to protocols}}
69+
blackHole(GCP<CP>()) // expected-error{{protocol 'CP' as a type cannot conform to the protocol itself; only concrete types such as structs, enums and classes can conform to protocols}}
7070
blackHole(GAO<P>()) // expected-error{{'GAO' requires that 'P' be a class type}}
7171
blackHole(GAO<OP>())
7272
blackHole(GAO<CP>()) // expected-error{{'GAO' requires that 'CP' be a class type}}
@@ -92,5 +92,5 @@ func foo() {
9292
// generic no overloads error path. The error should actually talk
9393
// about the return type, and this can happen in other contexts as well;
9494
// <rdar://problem/21900971> tracks improving QoI here.
95-
allMine.takeAll() // expected-error{{value of protocol type 'Mine' cannot conform to 'Mine'; only struct/enum/class types can conform to protocols}}
95+
allMine.takeAll() // expected-error{{protocol 'Mine' as a type cannot conform to the protocol itself; only concrete types such as structs, enums and classes can conform to protocols}}
9696
}

test/Misc/misc_diagnostics.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ func test17875634() {
143143
func test20770032() {
144144
if case let 1...10 = (1, 1) { // expected-warning{{'let' pattern has no effect; sub-pattern didn't bind any variables}} {{11-15=}}
145145
// expected-error@-1 {{expression pattern of type 'ClosedRange<Int>' cannot match values of type '(Int, Int)'}}
146-
// expected-error@-2 {{'(Int, Int)' cannot conform to 'Equatable'; only struct/enum/class types can conform to protocols}}
146+
// expected-error@-2 {{type '(Int, Int)' cannot conform to 'Equatable'; only concrete types such as structs, enums and classes can conform to protocols}}
147147
// expected-note@-3 {{required by operator function '~=' where 'T' = '(Int, Int)'}}
148148
}
149149
}

0 commit comments

Comments
 (0)