Skip to content

Commit 40985b6

Browse files
committed
[Diagnostics] Generalize the "protocol type cannot conform" error to
work for all types that cannot conform to protocols.
1 parent 0434d58 commit 40985b6

File tree

16 files changed

+47
-36
lines changed

16 files changed

+47
-36
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1660,10 +1660,9 @@ ERROR(cannot_use_nil_with_this_type,none,
16601660
ERROR(use_of_equal_instead_of_equality,none,
16611661
"use of '=' in a boolean context, did you mean '=='?", ())
16621662

1663-
1664-
ERROR(protocol_does_not_conform_objc,none,
1665-
"protocol type %0 cannot conform to %1 because only concrete "
1666-
"types can conform to protocols", (Type, Type))
1663+
ERROR(type_cannot_conform, none,
1664+
"%0 type %1 cannot conform to %2; only struct/enum/class "
1665+
"types can conform to protocols", (StringRef, Type, Type))
16671666
ERROR(protocol_does_not_conform_static,none,
16681667
"%0 cannot be used as a type conforming to protocol %1 because %1 "
16691668
"has static requirements",

lib/Sema/CSDiagnostics.cpp

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -570,13 +570,26 @@ bool MissingConformanceFailure::diagnoseAsError() {
570570
}
571571
}
572572

573-
if (nonConformingType->isExistentialType()) {
574-
auto diagnostic = diag::protocol_does_not_conform_objc;
575-
if (nonConformingType->isObjCExistentialType())
576-
diagnostic = diag::protocol_does_not_conform_static;
573+
if (nonConformingType->isObjCExistentialType()) {
574+
emitDiagnostic(anchor->getLoc(), diag::protocol_does_not_conform_static,
575+
nonConformingType, protocolType);
576+
return true;
577+
}
577578

578-
emitDiagnostic(anchor->getLoc(), diagnostic, nonConformingType,
579-
protocolType);
579+
// Diagnose types that cannot conform to protocols.
580+
Optional<StringRef> prohibitedTypeKind = None;
581+
if (nonConformingType->is<AnyFunctionType>())
582+
prohibitedTypeKind = "function";
583+
else if (nonConformingType->is<TupleType>())
584+
prohibitedTypeKind = "tuple";
585+
else if (nonConformingType->isExistentialType())
586+
prohibitedTypeKind = "protocol";
587+
else if (nonConformingType->is<AnyMetatypeType>())
588+
prohibitedTypeKind = "metatype";
589+
590+
if (prohibitedTypeKind.hasValue()) {
591+
emitDiagnostic(anchor->getLoc(), diag::type_cannot_conform,
592+
*prohibitedTypeKind, nonConformingType, protocolType);
580593
return true;
581594
}
582595

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3970,7 +3970,7 @@ static void diagnoseConformanceFailure(Type T,
39703970
TypeChecker::containsProtocol(T, Proto, DC, None)) {
39713971

39723972
if (!T->isObjCExistentialType()) {
3973-
diags.diagnose(ComplainLoc, diag::protocol_does_not_conform_objc,
3973+
diags.diagnose(ComplainLoc, diag::type_cannot_conform, "protocol",
39743974
T, Proto->getDeclaredType());
39753975
return;
39763976
}

test/Constraints/diagnostics.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ f0(i, i,
4747

4848

4949
// Position mismatch
50-
f5(f4) // expected-error {{argument type '(Int) -> Int' does not conform to expected type 'P2'}}
50+
f5(f4) // expected-error {{function type '(Int) -> Int' cannot conform to 'P2'; only struct/enum/class types can conform to protocols}}
5151

5252
// Tuple element not convertible.
5353
f0(i,
@@ -97,7 +97,7 @@ func f8<T:P2>(_ n: T, _ f: @escaping (T) -> T) {}
9797
f8(3, f4) // expected-error {{argument type 'Int' does not conform to expected type 'P2'}}
9898
typealias Tup = (Int, Double)
9999
func f9(_ x: Tup) -> Tup { return x }
100-
f8((1,2.0), f9) // expected-error {{argument type 'Tup' (aka '(Int, Double)') does not conform to expected type 'P2'}}
100+
f8((1,2.0), f9) // expected-error {{tuple type 'Tup' (aka '(Int, Double)') cannot conform to 'P2'; only struct/enum/class types can conform to protocols}}
101101

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

test/Constraints/function_builder_diags.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ struct TupleP<U> : P {
144144

145145
@_functionBuilder
146146
struct Builder {
147-
static func buildBlock<S0, S1>(_ stmt1: S0, _ stmt2: S1) // expected-note {{where 'S1' = 'Label<Any>.Type'}}
147+
static func buildBlock<S0, S1>(_ stmt1: S0, _ stmt2: S1)
148148
-> TupleP<(S0, S1)> where S0: P, S1: P {
149149
return TupleP((stmt1, stmt2))
150150
}
@@ -166,7 +166,7 @@ struct Label<L> : P where L : P { // expected-note {{'L' declared as parameter t
166166
}
167167

168168
func test_51167632() -> some P {
169-
AnyP(G { // expected-error {{static method 'buildBlock' requires that 'Label<Any>.Type' conform to 'P'}}
169+
AnyP(G { // expected-error {{metatype type 'Label<Any>.Type' cannot conform to 'P'; only struct/enum/class types can conform to protocols}}
170170
Text("hello")
171171
Label // expected-error {{generic parameter 'L' could not be inferred}}
172172
// 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
@@ -191,7 +191,7 @@ func r22459135() {
191191

192192
// <rdar://problem/19710848> QoI: Friendlier error message for "[] as Set"
193193
// <rdar://problem/22326930> QoI: "argument for generic parameter 'Element' could not be inferred" lacks context
194-
_ = [] as Set // expected-error {{protocol type 'Any' cannot conform to 'Hashable' because only concrete types can conform to protocols}}
194+
_ = [] as Set // expected-error {{protocol type 'Any' cannot conform to 'Hashable'; only struct/enum/class types can conform to protocols}}
195195

196196

197197
//<rdar://problem/22509125> QoI: Error when unable to infer generic archetype lacks greatness

test/Constraints/operator.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ func rdar46459603() {
220220
// expected-error@-1 {{binary operator '==' cannot be applied to operands of type 'Dictionary<String, E>.Values' and '[E]'}}
221221
// expected-note@-2 {{expected an argument list of type '(Self, Self)'}}
222222
_ = [arr.values] == [[e]]
223-
// expected-error@-1 {{protocol type 'Any' cannot conform to 'Equatable' because only concrete types can conform to protocols}}
223+
// expected-error@-1 {{protocol type 'Any' cannot conform to 'Equatable'; only struct/enum/class types can conform to protocols}}
224224
}
225225

226226
// SR-10843

test/Generics/conditional_conformances_literals.swift

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

128128
// Needs self conforming protocols:
129129
let _: Conforms = [[0: [1 : [works]] as Conforms]]
130-
// expected-error@-1 {{protocol type 'Conforms' cannot conform to 'Conforms' because only concrete types can conform to protocols}}
130+
// expected-error@-1 {{protocol type 'Conforms' cannot conform to 'Conforms'; only struct/enum/class types can conform to protocols}}
131131

132132
let _: Conforms = [[0: [1 : [fails]] as Conforms]]
133133
// expected-error@-1 {{protocol 'Conforms' requires that 'Fails' conform to 'Conforms'}}
134-
// expected-error@-2 {{protocol type 'Conforms' cannot conform to 'Conforms' because only concrete types can conform to protocols}}
134+
// expected-error@-2 {{protocol type 'Conforms' cannot conform to 'Conforms'; only struct/enum/class types can conform to protocols}}
135135
}

test/Generics/existential_restrictions.swift

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

1919
func testPassExistential(_ p: P, op: OP, opp: OP & P, cp: CP, sp: SP, any: Any, ao: AnyObject) {
20-
fP(p) // expected-error{{protocol type 'P' cannot conform to 'P' because only concrete types can conform to protocols}}
20+
fP(p) // expected-error{{protocol type 'P' cannot conform to 'P'; only struct/enum/class types can conform to protocols}}
2121
fAO(p) // expected-error{{cannot invoke 'fAO' with an argument list of type '(P)'}} // expected-note{{expected an argument list of type '(T)'}}
2222
fAOE(p) // expected-error{{argument type 'P' does not conform to expected type 'AnyObject'}}
2323
fT(p)
@@ -31,8 +31,8 @@ func testPassExistential(_ p: P, op: OP, opp: OP & P, cp: CP, sp: SP, any: Any,
3131
fAOE(cp)
3232
fT(cp)
3333

34-
fP(opp) // expected-error{{protocol type 'OP & P' cannot conform to 'P' because only concrete types can conform to protocols}}
35-
fOP(opp) // expected-error{{protocol type 'OP & P' cannot conform to 'OP' because only concrete types can conform to protocols}}
34+
fP(opp) // expected-error{{protocol type 'OP & P' cannot conform to 'P'; only struct/enum/class types can conform to protocols}}
35+
fOP(opp) // expected-error{{protocol type 'OP & P' cannot conform to 'OP'; only struct/enum/class types can conform to protocols}}
3636
fAO(opp) // expected-error{{cannot invoke 'fAO' with an argument list of type '(OP & P)'}} // expected-note{{expected an argument list of type '(T)'}}
3737
fAOE(opp)
3838
fT(opp)
@@ -58,9 +58,9 @@ class GAO<T : AnyObject> {} // expected-note 2{{requirement specified as 'T' : '
5858
func blackHole(_ t: Any) {}
5959

6060
func testBindExistential() {
61-
blackHole(GP<P>()) // expected-error{{protocol type 'P' cannot conform to 'P' because only concrete types can conform to protocols}}
61+
blackHole(GP<P>()) // expected-error{{protocol type 'P' cannot conform to 'P'; only struct/enum/class types can conform to protocols}}
6262
blackHole(GOP<OP>())
63-
blackHole(GCP<CP>()) // expected-error{{protocol type 'CP' cannot conform to 'CP' because only concrete types can conform to protocols}}
63+
blackHole(GCP<CP>()) // expected-error{{protocol type 'CP' cannot conform to 'CP'; only struct/enum/class types can conform to protocols}}
6464
blackHole(GAO<P>()) // expected-error{{'GAO' requires that 'P' be a class type}}
6565
blackHole(GAO<OP>())
6666
blackHole(GAO<CP>()) // expected-error{{'GAO' requires that 'CP' be a class type}}
@@ -85,5 +85,5 @@ func foo() {
8585
// generic no overloads error path. The error should actually talk
8686
// about the return type, and this can happen in other contexts as well;
8787
// <rdar://problem/21900971> tracks improving QoI here.
88-
allMine.takeAll() // expected-error{{protocol type 'Mine' cannot conform to 'Mine' because only concrete types can conform to protocols}}
88+
allMine.takeAll() // expected-error{{protocol type 'Mine' cannot conform to 'Mine'; only struct/enum/class types can conform to protocols}}
8989
}

test/decl/protocol/conforms/error_self_conformance.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,15 @@ func testSimple(error: Error) {
88

99
protocol ErrorRefinement : Error {}
1010
func testErrorRefinment(error: ErrorRefinement) {
11-
wantsError(error) // expected-error {{protocol type 'ErrorRefinement' cannot conform to 'Error' because only concrete types can conform to protocols}}
11+
wantsError(error) // expected-error {{protocol type 'ErrorRefinement' cannot conform to 'Error'; only struct/enum/class types can conform to protocols}}
1212
}
1313

1414
protocol OtherProtocol {}
1515
func testErrorComposition(error: Error & OtherProtocol) {
16-
wantsError(error) // expected-error {{protocol type 'Error & OtherProtocol' cannot conform to 'Error' because only concrete types can conform to protocols}}
16+
wantsError(error) // expected-error {{protocol type 'Error & OtherProtocol' cannot conform to 'Error'; only struct/enum/class types can conform to protocols}}
1717
}
1818

1919
class C {}
2020
func testErrorCompositionWithClass(error: Error & C) {
21-
wantsError(error) // expected-error {{protocol type 'C & Error' cannot conform to 'Error' because only concrete types can conform to protocols}}
21+
wantsError(error) // expected-error {{protocol type 'C & Error' cannot conform to 'Error'; only struct/enum/class types can conform to protocols}}
2222
}

0 commit comments

Comments
 (0)