Skip to content

Commit c8690b3

Browse files
committed
[CSBindings] Don't prioritize closures that are assigned to overloaded members
Constraint generation uses a special pattern while generating constraints for assignments to make sure that the source type is convertible to r-value type of the destination. `BindingSet::favoredOverDisjunction` needs to recognize this pattern, where disjunction type variable is bound early, and avoid prioritizing closure if it's connected to the "fixed type" of the disjunction or risk losing annotations associated with the member such as `@Sendable` or a global actor. Resolves: rdar://131524246
1 parent d88b799 commit c8690b3

File tree

2 files changed

+46
-1
lines changed

2 files changed

+46
-1
lines changed

lib/Sema/CSBindings.cpp

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1318,7 +1318,30 @@ bool BindingSet::favoredOverDisjunction(Constraint *disjunction) const {
13181318
// Such type variables might be connected to closure as well
13191319
// e.g. when result type is optional, so it makes sense to
13201320
// open closure before attempting such disjunction.
1321-
return boundType->lookThroughAllOptionalTypes()->is<TypeVariableType>();
1321+
if (auto *typeVar = boundType->lookThroughAllOptionalTypes()
1322+
->getAs<TypeVariableType>()) {
1323+
auto fixedType = CS.getFixedType(typeVar);
1324+
// Handles "assignment to an overloaded member" pattern where
1325+
// type variable that represents the destination is bound to an
1326+
// l-value type during constraint generation. See \c genAssignDestType.
1327+
//
1328+
// Note that in all other circumstances we won't be here if the
1329+
// type variable that presents the closure is connected to a
1330+
// disjunction because that would mark closure as "delayed".
1331+
if (fixedType && fixedType->is<LValueType>()) {
1332+
auto lvalueObjTy = fixedType->castTo<LValueType>()->getObjectType();
1333+
// Prefer closure only if it's not connected to the type variable
1334+
// that represents l-value object type of the assignment destination.
1335+
// Eagerly attempting closure first could result in missing some of
1336+
// the contextual annotations i.e. `@Sendable`.
1337+
if (auto *lvalueObjVar = lvalueObjTy->getAs<TypeVariableType>())
1338+
return !AdjacentVars.count(lvalueObjVar);
1339+
}
1340+
1341+
return true;
1342+
}
1343+
1344+
return false;
13221345
}
13231346

13241347
// If this is a collection literal type, it's preferrable to bind it
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// RUN: %target-typecheck-verify-swift -swift-version 5
2+
// RUN: %target-typecheck-verify-swift -swift-version 5 -strict-concurrency=complete
3+
// RUN: %target-typecheck-verify-swift -swift-version 6
4+
5+
// rdar://131524246
6+
7+
protocol P: Sendable {
8+
typealias Block = @Sendable () -> Void
9+
var block: Block? { get }
10+
}
11+
12+
extension P {
13+
var block: Block? { nil }
14+
}
15+
16+
final class Impl: P, @unchecked Sendable {
17+
var block: Block?
18+
}
19+
20+
func test(_ v: Impl) {
21+
v.block = {} // Ok, no warnings or errors
22+
}

0 commit comments

Comments
 (0)