From 359bd4d691ec0a4694f70d49b6a9a7e33c898989 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Thu, 9 Oct 2025 17:55:25 -0400 Subject: [PATCH] Sema: Fix concurrency adjustment for member operator references There was a typo in the code which made us ignore the result of the adjusted operator reference. This was a regression from commit 1efc9a6d0db3941400e8c320712bcec5099e1ea3. It doesn't actually matter if an immediately-applied function reference is `@Sendable` or not... But, there is another hack in CSApply which devirtualizes a call to a member operator in a protocol, and the `@Sendable` mismatch made us *skip* this hack. Skipping the devirtualization hack, in turn, allowed code that calls `==` on two Foundation.Data instances to type check with MemberImportVisibility off. Once again, this is probably a mistake, but it caused a regression where existing code stopped working. Ideally, we should teach MemberImportVisibility about conformances, remove the devirtualization hack, and also skip the `@Sendable` adjustment except when the member reference is unapplied. But the existing logic was clearly wrong, so let's fix it. Fixes rdar://162130647. --- lib/Sema/TypeOfReference.cpp | 26 +++++++++---------- .../member_operator_adjustment.swift | 7 +++++ 2 files changed, 19 insertions(+), 14 deletions(-) create mode 100644 test/Concurrency/member_operator_adjustment.swift diff --git a/lib/Sema/TypeOfReference.cpp b/lib/Sema/TypeOfReference.cpp index bec20874a37fa..aae9add5b6456 100644 --- a/lib/Sema/TypeOfReference.cpp +++ b/lib/Sema/TypeOfReference.cpp @@ -43,8 +43,6 @@ using namespace inference; #define DEBUG_TYPE "ConstraintSystem" - - Type ConstraintSystem::openUnboundGenericType(GenericTypeDecl *decl, Type parentTy, ConstraintLocatorBuilder locator, @@ -1235,38 +1233,37 @@ ConstraintSystem::getTypeOfReferencePost(OverloadChoice choice, auto *value = choice.getDecl(); if (value->getDeclContext()->isTypeContext() && isa(value)) { - auto *openedFnType = openedType->castTo(); - // Unqualified lookup can find operator names within nominal types. auto func = cast(value); assert(func->isOperator() && "Lookup should only find operators"); auto functionRefInfo = choice.getFunctionRefInfo(); - auto origOpenedType = openedFnType; + auto origOpenedType = openedType; if (!isRequirementOrWitness(locator)) { unsigned numApplies = getNumApplications(/*hasAppliedSelf*/ false, functionRefInfo); - openedFnType = adjustFunctionTypeForConcurrency( - origOpenedType, /*baseType=*/Type(), func, useDC, numApplies, - /*isMainDispatchQueue=*/false, /*openGlobalActorType=*/true, locator); + openedType = adjustFunctionTypeForConcurrency( + origOpenedType->castTo(), /*baseType=*/Type(), + func, useDC, numApplies, /*isMainDispatchQueue=*/false, + /*openGlobalActorType=*/true, locator); } // If this is a method whose result type is dynamic Self, replace // DynamicSelf with the actual object type. Repeat the adjustment // for the original and adjusted types. - auto type = openedFnType; - if (openedFnType->hasDynamicSelfType()) { - auto params = openedFnType->getParams(); + auto type = openedType; + if (openedType->hasDynamicSelfType()) { + auto params = openedType->castTo()->getParams(); assert(params.size() == 1); Type selfTy = params.front().getPlainType()->getMetatypeInstanceType(); - type = openedFnType->replaceDynamicSelfType(selfTy) + type = openedType->replaceDynamicSelfType(selfTy) ->castTo(); } auto origType = origOpenedType; if (origOpenedType->hasDynamicSelfType()) { - auto params = origOpenedType->getParams(); + auto params = origOpenedType->castTo()->getParams(); assert(params.size() == 1); Type selfTy = params.front().getPlainType()->getMetatypeInstanceType(); origType = origOpenedType->replaceDynamicSelfType(selfTy) @@ -1275,7 +1272,8 @@ ConstraintSystem::getTypeOfReferencePost(OverloadChoice choice, // The reference implicitly binds 'self'. return {origOpenedType, openedType, - origType->getResult(), type->getResult(), Type()}; + origType->castTo()->getResult(), + type->castTo()->getResult(), Type()}; } // Unqualified reference to a local or global function. diff --git a/test/Concurrency/member_operator_adjustment.swift b/test/Concurrency/member_operator_adjustment.swift new file mode 100644 index 0000000000000..98a898a48792f --- /dev/null +++ b/test/Concurrency/member_operator_adjustment.swift @@ -0,0 +1,7 @@ +// RUN: %target-swift-frontend -dump-ast -swift-version 6 %s | %FileCheck %s + +// CHECK: (func_decl decl_context={{.*}} range={{.*}} "test(v:)" +func test(v: T) { + // CHECK: (function_conversion_expr implicit type="@Sendable (T.Type) -> (T, T) -> Bool" + _ = v == v +}