From 40948d7abd05f92a670f6120be1df1f6f55b5458 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Wed, 24 Sep 2025 17:58:22 -0400 Subject: [PATCH] Sema: Workaround for broken existential opening behavior This is a narrow workaround for a regression from 9e3d0e0a8c78076a70a9869d10acc6189cb7bb6b. There is no reason to skip this logic for protocol extension members, except that doing so happens to break existential opening in an expression that involves a call to Array.init elsewhere. However there is an underlying issue here with existential opening, which doesn't seem to work right in the presence of overloading. The test case demonstrates the fixed problem, together with an existing bug that points to the underlying problem. Fixes rdar://160389221. --- lib/Sema/CSSimplify.cpp | 6 +++- .../opened_existentials_overload.swift | 30 +++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 test/Constraints/opened_existentials_overload.swift diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 0ff46495538d7..2bf0aa0be444f 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -13394,8 +13394,12 @@ bool ConstraintSystem::simplifyAppliedOverloadsImpl( choiceType = objectType; } + // FIXME: The !getSelfProtocolDecl() check is load-bearing, because + // this optimization interacts poorly with existential opening + // somehow. It should all be removed. if (auto *choiceFnType = choiceType->getAs()) { - if (isa(choice.getDecl())) { + if (isa(choice.getDecl()) && + !choice.getDecl()->getDeclContext()->getSelfProtocolDecl()) { auto choiceResultType = choice.getBaseType() ->getRValueType() ->getMetatypeInstanceType(); diff --git a/test/Constraints/opened_existentials_overload.swift b/test/Constraints/opened_existentials_overload.swift new file mode 100644 index 0000000000000..28eb4c1243a6a --- /dev/null +++ b/test/Constraints/opened_existentials_overload.swift @@ -0,0 +1,30 @@ +// RUN: %target-typecheck-verify-swift + +protocol P {} + +func g(_: some P) {} +// expected-note@-1 {{required by global function 'g' where 'some P' = 'any P'}} + +// rdar://problem/160389221 +func good(_ x: Array) { + Array(x).forEach { y in g(y) } +} + +extension Array { + var ffirst: Element? { fatalError() } + func ffirst(wwhere: (Element) -> Bool) -> Element { fatalError() } +} + +func bad(_ x: Array) { + let y = x.ffirst! + g(y) // ok + + let yy = x.ffirst + g(yy!) // ok + + // FIXME: This is broken + + g(x.ffirst!) + // expected-error@-1 {{type 'any P' cannot conform to 'P'}} + // expected-note@-2 {{only concrete types such as structs, enums and classes can conform to protocols}} +}