Skip to content

[Diagnostics] Split "only concrete types conform to protocols" into a separate note #34467

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Oct 28, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -1842,9 +1842,11 @@ ERROR(use_of_equal_instead_of_equality,none,
"use of '=' in a boolean context, did you mean '=='?", ())
ERROR(type_cannot_conform, none,
"%select{type %1|protocol %1 as a type}0 cannot conform to "
"%select{%3|the protocol itself}2; "
"only concrete types such as structs, enums and classes can conform to protocols",
"%select{%3|the protocol itself}2",
(bool, Type, bool, Type))
NOTE(only_concrete_types_conform_to_protocols,none,
"only concrete types such as structs, enums and classes can conform to protocols",
())
NOTE(required_by_opaque_return,none,
"required by opaque return type of %0 %1", (DescriptiveDeclKind, DeclName))
NOTE(required_by_decl,none,
Expand Down
3 changes: 3 additions & 0 deletions lib/Sema/CSDiagnostics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,8 @@ bool MissingConformanceFailure::diagnoseTypeCannotConform(
nonConformingType->isEqual(protocolType),
protocolType);

emitDiagnostic(diag::only_concrete_types_conform_to_protocols);

if (auto *OTD = dyn_cast<OpaqueTypeDecl>(AffectedDecl)) {
auto *namingDecl = OTD->getNamingDecl();
if (auto *repr = namingDecl->getOpaqueResultTypeRepr()) {
Expand Down Expand Up @@ -2171,6 +2173,7 @@ bool ContextualFailure::diagnoseAsError() {
emitDiagnostic(diag::type_cannot_conform,
/*isExistentialType=*/true, fromType,
fromType->isEqual(toType), toType);
emitDiagnostic(diag::only_concrete_types_conform_to_protocols);
return true;
}

Expand Down
2 changes: 2 additions & 0 deletions lib/Sema/TypeCheckProtocol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4735,6 +4735,8 @@ void swift::diagnoseConformanceFailure(Type T,
diags.diagnose(ComplainLoc, diag::type_cannot_conform, true,
T, T->isEqual(Proto->getDeclaredInterfaceType()),
Proto->getDeclaredInterfaceType());
diags.diagnose(ComplainLoc,
diag::only_concrete_types_conform_to_protocols);
return;
}

Expand Down
8 changes: 4 additions & 4 deletions test/Constraints/diagnostics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ f0(i, i, // expected-error@:7 {{cannot convert value of type 'Int' to expected a


// Cannot conform to protocols.
f5(f4) // expected-error {{type '(Int) -> Int' cannot conform to 'P2'; only concrete types such as structs, enums and classes can conform to protocols}}
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}}
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}}
f5(f4) // expected-error {{type '(Int) -> Int' cannot conform to 'P2'}} expected-note {{only concrete types such as structs, enums and classes can conform to protocols}}
f5((1, "hello")) // expected-error {{type '(Int, String)' cannot conform to 'P2'}} expected-note {{only concrete types such as structs, enums and classes can conform to protocols}}
f5(Int.self) // expected-error {{type 'Int.Type' cannot conform to 'P2'}} expected-note {{only concrete types such as structs, enums and classes can conform to protocols}}

// Tuple element not convertible.
f0(i,
Expand Down Expand Up @@ -104,7 +104,7 @@ func f8<T:P2>(_ n: T, _ f: @escaping (T) -> T) {} // expected-note {{where 'T'
f8(3, f4) // expected-error {{global function 'f8' requires that 'Int' conform to 'P2'}}
typealias Tup = (Int, Double)
func f9(_ x: Tup) -> Tup { return x }
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}}
f8((1,2.0), f9) // expected-error {{type 'Tup' (aka '(Int, Double)') cannot conform to 'P2'}} expected-note {{only concrete types such as structs, enums and classes can conform to protocols}}

// <rdar://problem/19658691> QoI: Incorrect diagnostic for calling nonexistent members on literals
1.doesntExist(0) // expected-error {{value of type 'Int' has no member 'doesntExist'}}
Expand Down
2 changes: 1 addition & 1 deletion test/Constraints/generics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ func r22459135() {

// <rdar://problem/19710848> QoI: Friendlier error message for "[] as Set"
// <rdar://problem/22326930> QoI: "argument for generic parameter 'Element' could not be inferred" lacks context
_ = [] 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}}
_ = [] as Set // expected-error {{protocol 'Any' as a type cannot conform to 'Hashable'}} expected-note {{only concrete types such as structs, enums and classes can conform to protocols}}
// expected-note@-1 {{required by generic struct 'Set' where 'Element' = 'Any'}}


Expand Down
2 changes: 1 addition & 1 deletion test/Constraints/rdar68155466.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,4 @@ func data() -> [A] {
}

_ = Loop(data(), id: \.uniqueID) { $0 } // expected-error {{key path cannot refer to instance method 'uniqueID()'}}
// expected-error@-1 {{type '() -> Int' cannot conform to 'Hashable'; only concrete types such as structs, enums and classes can conform to protocols}}
// expected-error@-1 {{type '() -> Int' cannot conform to 'Hashable'}} expected-note@-1 {{only concrete types such as structs, enums and classes can conform to protocols}}
2 changes: 1 addition & 1 deletion test/Constraints/result_builder_diags.swift
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ struct Label<L> : P where L : P { // expected-note 2 {{'L' declared as parameter
}

func test_51167632() -> some P {
AnyP(G { // expected-error {{type 'Label<_>.Type' cannot conform to 'P'; only concrete types such as structs, enums and classes can conform to protocols}}
AnyP(G { // expected-error {{type 'Label<_>.Type' cannot conform to 'P'}} expected-note {{only concrete types such as structs, enums and classes can conform to protocols}}
Text("hello")
Label // expected-error {{generic parameter 'L' could not be inferred}}
// expected-note@-1 {{explicitly specify the generic arguments to fix this issue}} {{10-10=<<#L: P#>>}}
Expand Down
4 changes: 2 additions & 2 deletions test/Generics/conditional_conformances_literals.swift
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,9 @@ func combined() {

// Needs self conforming protocols:
let _: Conforms = [[0: [1 : [works]] as Conforms]]
// 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}}
// expected-error@-1 {{protocol 'Conforms' as a type cannot conform to the protocol itself}} expected-note@-1 {{only concrete types such as structs, enums and classes can conform to protocols}}

let _: Conforms = [[0: [1 : [fails]] as Conforms]]
// expected-error@-1 {{protocol 'Conforms' requires that 'Fails' conform to 'Conforms'}}
// 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}}
// expected-error@-2 {{protocol 'Conforms' as a type cannot conform to the protocol itself}} expected-note@-2 {{only concrete types such as structs, enums and classes can conform to protocols}}
}
12 changes: 6 additions & 6 deletions test/Generics/existential_restrictions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func fAOE(_ t: AnyObject) { }
func fT<T>(_ t: T) { }

func testPassExistential(_ p: P, op: OP, opp: OP & P, cp: CP, sp: SP, any: Any, ao: AnyObject) {
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}}
fP(p) // expected-error{{protocol 'P' as a type cannot conform to the protocol itself}} expected-note {{only concrete types such as structs, enums and classes can conform to protocols}}
fAO(p) // expected-error{{global function 'fAO' requires that 'P' be a class type}}
fAOE(p) // expected-error{{argument type 'P' expected to be an instance of a class or class-constrained type}}
fT(p)
Expand All @@ -37,8 +37,8 @@ func testPassExistential(_ p: P, op: OP, opp: OP & P, cp: CP, sp: SP, any: Any,
fAOE(cp)
fT(cp)

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}}
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}}
fP(opp) // expected-error{{protocol 'OP & P' as a type cannot conform to 'P'}} expected-note {{only concrete types such as structs, enums and classes can conform to protocols}}
fOP(opp) // expected-error{{protocol 'OP & P' as a type cannot conform to 'OP'}} expected-note {{only concrete types such as structs, enums and classes can conform to protocols}}
fAO(opp) // expected-error{{global function 'fAO' requires that 'OP & P' be a class type}}
fAOE(opp)
fT(opp)
Expand All @@ -64,9 +64,9 @@ class GAO<T : AnyObject> {} // expected-note 2{{requirement specified as 'T' : '
func blackHole(_ t: Any) {}

func testBindExistential() {
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}}
blackHole(GP<P>()) // expected-error{{protocol 'P' as a type cannot conform to the protocol itself}} expected-note {{only concrete types such as structs, enums and classes can conform to protocols}}
blackHole(GOP<OP>())
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}}
blackHole(GCP<CP>()) // expected-error{{protocol 'CP' as a type cannot conform to the protocol itself}} expected-note {{only concrete types such as structs, enums and classes can conform to protocols}}
blackHole(GAO<P>()) // expected-error{{'GAO' requires that 'P' be a class type}}
blackHole(GAO<OP>())
blackHole(GAO<CP>()) // expected-error{{'GAO' requires that 'CP' be a class type}}
Expand All @@ -92,5 +92,5 @@ func foo() {
// generic no overloads error path. The error should actually talk
// about the return type, and this can happen in other contexts as well;
// <rdar://problem/21900971> tracks improving QoI here.
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}}
allMine.takeAll() // expected-error{{protocol 'Mine' as a type cannot conform to the protocol itself}} expected-note {{only concrete types such as structs, enums and classes can conform to protocols}}
}
3 changes: 2 additions & 1 deletion test/Parse/confusables.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@ if (true ꝸꝸꝸ false) {} // expected-note {{identifier 'ꝸꝸꝸ' contains

// expected-error @+3 {{invalid character in source file}}
// expected-error @+2 {{expected ',' separator}}
// expected-error @+1 {{type '(Int, Int)' cannot conform to 'BinaryInteger'; only concrete types such as structs, enums and classes can conform to protocols}}
// expected-error @+1 {{type '(Int, Int)' cannot conform to 'BinaryInteger'}}
if (5 ‒ 5) == 0 {} // expected-note {{unicode character '‒' (Figure Dash) looks similar to '-' (Hyphen Minus); did you mean to use '-' (Hyphen Minus)?}} {{7-10=-}}
// expected-note @-1 {{operator function '=='}}
// expected-note @-2 {{only concrete types such as structs, enums and classes can conform to protocols}}

// FIXME(rdar://61028087): The above note should read "required by referencing operator function '==' on 'BinaryInteger' where 'Self' = '(Int, Int)'".

Expand Down
6 changes: 3 additions & 3 deletions test/decl/protocol/conforms/error_self_conformance.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ func testSimple(error: Error) {

protocol ErrorRefinement : Error {}
func testErrorRefinment(error: ErrorRefinement) {
wantsError(error) // expected-error {{protocol 'ErrorRefinement' as a type cannot conform to 'Error'; only concrete types such as structs, enums and classes can conform to protocols}}
wantsError(error) // expected-error {{protocol 'ErrorRefinement' as a type cannot conform to 'Error'}} expected-note {{only concrete types such as structs, enums and classes can conform to protocols}}
}

protocol OtherProtocol {}
func testErrorComposition(error: Error & OtherProtocol) {
wantsError(error) // expected-error {{protocol 'Error & OtherProtocol' as a type cannot conform to 'Error'; only concrete types such as structs, enums and classes can conform to protocols}}
wantsError(error) // expected-error {{protocol 'Error & OtherProtocol' as a type cannot conform to 'Error'}} expected-note {{only concrete types such as structs, enums and classes can conform to protocols}}
}

class C {}
func testErrorCompositionWithClass(error: Error & C) {
wantsError(error) // expected-error {{protocol 'C & Error' as a type cannot conform to 'Error'; only concrete types such as structs, enums and classes can conform to protocols}}
wantsError(error) // expected-error {{protocol 'C & Error' as a type cannot conform to 'Error'}} expected-note {{only concrete types such as structs, enums and classes can conform to protocols}}
}
2 changes: 1 addition & 1 deletion test/stmt/foreach.swift
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ func testOptionalSequence() {

// Crash with (invalid) for each over an existential
func testExistentialSequence(s: Sequence) { // expected-error {{protocol 'Sequence' can only be used as a generic constraint because it has Self or associated type requirements}}
for x in s { // expected-error {{protocol 'Sequence' as a type cannot conform to the protocol itself; only concrete types such as structs, enums and classes can conform to protocols}}
for x in s { // expected-error {{protocol 'Sequence' as a type cannot conform to the protocol itself}} expected-note {{only concrete types such as structs, enums and classes can conform to protocols}}
_ = x
}
}
Expand Down
2 changes: 1 addition & 1 deletion test/type/opaque.swift
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ protocol P_51641323 {
func rdar_51641323() {
struct Foo: P_51641323 {
var foo: some P_51641323 { // expected-note {{required by opaque return type of property 'foo'}}
{} // expected-error {{type '() -> ()' cannot conform to 'P_51641323'; only concrete types such as structs, enums and classes can conform to protocols}}
{} // expected-error {{type '() -> ()' cannot conform to 'P_51641323'}} expected-note {{only concrete types such as structs, enums and classes can conform to protocols}}
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion test/type/subclass_composition.swift
Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,8 @@ func conformsTo<T1 : P2, T2 : Base<Int> & P2>(
// expected-error@-1 {{global function 'conformsToAnyObject' requires that 'P1' be a class type}}

conformsToP1(p1)
// expected-error@-1 {{protocol 'P1' as a type cannot conform to the protocol itself; only concrete types such as structs, enums and classes can conform to protocols}}
// expected-error@-1 {{protocol 'P1' as a type cannot conform to the protocol itself}}
// expected-note@-2 {{only concrete types such as structs, enums and classes can conform to protocols}}

// FIXME: Following diagnostics are not great because when
// `conformsTo*` methods are re-typechecked, they loose information
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ func fn<T, U: P>(_ arg1: T, arg2: (T) -> U) {}
// expected-note@-1 {{required by global function 'fn(_:arg2:)' where 'U' = '()'}}

func test(str: String) {
fn(str) { arg in // expected-error {{type '()' cannot conform to 'P'; only concrete types such as structs, enums and classes can conform to protocols}}
fn(str) { arg in // expected-error {{type '()' cannot conform to 'P'}} expected-note {{only concrete types such as structs, enums and classes can conform to protocols}}
<#FOO#> // expected-error {{editor placeholder in source file}}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,4 @@ extension Bool : BooleanProtocol {
func f<T : BooleanProtocol>(_ b: T) {}
// expected-note@-1 {{required by global function 'f' where 'T' = 'BooleanProtocol'}}

f(true as BooleanProtocol) // expected-error {{protocol 'BooleanProtocol' as a type cannot conform to the protocol itself; only concrete types such as structs, enums and classes can conform to protocols}}
f(true as BooleanProtocol) // expected-error {{protocol 'BooleanProtocol' as a type cannot conform to the protocol itself}} expected-note {{only concrete types such as structs, enums and classes can conform to protocols}}