From 8ce878f7e3a00f8f15be51040519649da96e349d Mon Sep 17 00:00:00 2001 From: "mdietsche@icloud.com" Date: Sun, 8 May 2022 01:53:37 +0200 Subject: [PATCH] Do not suggest moving `any` or `some` to the beginning of a composition if the first type is already an existential or opaque type. --- lib/Parse/ParseType.cpp | 15 +++++++++++---- test/type/explicit_existential.swift | 10 ++++++---- test/type/opaque.swift | 5 ++++- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/lib/Parse/ParseType.cpp b/lib/Parse/ParseType.cpp index 16feac79393db..3d732e62d57bd 100644 --- a/lib/Parse/ParseType.cpp +++ b/lib/Parse/ParseType.cpp @@ -881,13 +881,20 @@ Parser::parseTypeSimpleOrComposition(Diag<> MessageID, ParseTypeReason reason) { Tok.isContextualKeyword("any")) { auto keyword = Tok.getText(); auto badLoc = consumeToken(); + + // Suggest moving `some` or `any` in front of the first type unless + // the first type is an opaque or existential type. + if (opaqueLoc.isValid() || anyLoc.isValid()) { + diagnose(badLoc, diag::opaque_mid_composition, keyword) + .fixItRemove(badLoc); + } else { + diagnose(badLoc, diag::opaque_mid_composition, keyword) + .fixItRemove(badLoc) + .fixItInsert(FirstTypeLoc, keyword.str() + " "); + } const bool isAnyKeyword = keyword.equals("any"); - diagnose(badLoc, diag::opaque_mid_composition, keyword) - .fixItRemove(badLoc) - .fixItInsert(FirstTypeLoc, keyword.str() + " "); - if (isAnyKeyword) { if (anyLoc.isInvalid()) { anyLoc = badLoc; diff --git a/test/type/explicit_existential.swift b/test/type/explicit_existential.swift index 340ad8b705397..aa706b63167e2 100644 --- a/test/type/explicit_existential.swift +++ b/test/type/explicit_existential.swift @@ -156,15 +156,17 @@ func anyAny() { protocol P1 {} protocol P2 {} +protocol P3 {} do { // Test that we don't accidentally misparse an 'any' type as a 'some' type // and vice versa. - let _: P1 & any P2 // expected-error {{'any' should appear at the beginning of a composition}} - let _: any P1 & any P2 // expected-error {{'any' should appear at the beginning of a composition}} - let _: any P1 & some P2 // expected-error {{'some' should appear at the beginning of a composition}} + let _: P1 & any P2 // expected-error {{'any' should appear at the beginning of a composition}} {{15-19=}} {{10-10=any }} + let _: any P1 & any P2 // expected-error {{'any' should appear at the beginning of a composition}} {{19-23=}} + let _: any P1 & P2 & any P3 // expected-error {{'any' should appear at the beginning of a composition}} {{24-28=}} + let _: any P1 & some P2 // expected-error {{'some' should appear at the beginning of a composition}} {{19-24=}} let _: some P1 & any P2 // expected-error@-1 {{'some' type can only be declared on a single property declaration}} - // expected-error@-2 {{'any' should appear at the beginning of a composition}} + // expected-error@-2 {{'any' should appear at the beginning of a composition}} {{20-24=}} } struct ConcreteComposition: P1, P2 {} diff --git a/test/type/opaque.swift b/test/type/opaque.swift index b07882b922bd0..dc4fe826214ab 100644 --- a/test/type/opaque.swift +++ b/test/type/opaque.swift @@ -488,8 +488,11 @@ func foo_repl(_ s: S) -> some Proto { protocol SomeProtocolA {} protocol SomeProtocolB {} -struct SomeStructC: SomeProtocolA, SomeProtocolB {} +protocol SomeProtocolC {} +struct SomeStructC: SomeProtocolA, SomeProtocolB, SomeProtocolC {} let someProperty: SomeProtocolA & some SomeProtocolB = SomeStructC() // expected-error {{'some' should appear at the beginning of a composition}}{{35-40=}}{{19-19=some }} +let someOtherProperty: some SomeProtocolA & some SomeProtocolB = SomeStructC() // expected-error {{'some' should appear at the beginning of a composition}}{{45-50=}} +let someThirdProperty: some SomeProtocolA & SomeProtocolB & some SomeProtocolC = SomeStructC() // expected-error {{'some' should appear at the beginning of a composition}}{{61-66=}} // An opaque result type on a protocol extension member effectively // contains an invariant reference to 'Self', and therefore cannot