Skip to content

Commit 40c8da6

Browse files
committed
[ConstraintSystem] InferSendableFromCaptures: Start inferring sendability of key path expressions
When `InferSendableFromCaptures` feature is enabled `inferKeyPathLiteralCapability` should examine subscript arguments to determine whether the key path type is sendable or not, and if so, inform inference to produce `& Sendable` existential type as a binding. Binding key path type is delayed until all subscript arguments are fully resolved.
1 parent d727495 commit 40c8da6

File tree

2 files changed

+59
-16
lines changed

2 files changed

+59
-16
lines changed

lib/Sema/CSBindings.cpp

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -531,22 +531,41 @@ void BindingSet::inferTransitiveBindings(
531531
}
532532
}
533533

534-
static BoundGenericType *getKeyPathType(ASTContext &ctx,
535-
KeyPathCapability capability,
536-
Type rootType, Type valueType) {
537-
switch (capability.first) {
534+
static Type getKeyPathType(ASTContext &ctx, KeyPathCapability capability,
535+
Type rootType, Type valueType) {
536+
KeyPathMutability mutability;
537+
bool isSendable;
538+
539+
std::tie(mutability, isSendable) = capability;
540+
541+
Type keyPathTy;
542+
switch (mutability) {
538543
case KeyPathMutability::ReadOnly:
539-
return BoundGenericType::get(ctx.getKeyPathDecl(), /*parent=*/Type(),
540-
{rootType, valueType});
544+
keyPathTy = BoundGenericType::get(ctx.getKeyPathDecl(), /*parent=*/Type(),
545+
{rootType, valueType});
546+
break;
541547

542548
case KeyPathMutability::Writable:
543-
return BoundGenericType::get(ctx.getWritableKeyPathDecl(),
544-
/*parent=*/Type(), {rootType, valueType});
549+
keyPathTy = BoundGenericType::get(ctx.getWritableKeyPathDecl(),
550+
/*parent=*/Type(), {rootType, valueType});
551+
break;
545552

546553
case KeyPathMutability::ReferenceWritable:
547-
return BoundGenericType::get(ctx.getReferenceWritableKeyPathDecl(),
548-
/*parent=*/Type(), {rootType, valueType});
554+
keyPathTy = BoundGenericType::get(ctx.getReferenceWritableKeyPathDecl(),
555+
/*parent=*/Type(), {rootType, valueType});
556+
break;
557+
}
558+
559+
if (isSendable &&
560+
ctx.LangOpts.hasFeature(Feature::InferSendableFromCaptures)) {
561+
auto *sendable = ctx.getProtocol(KnownProtocolKind::Sendable);
562+
keyPathTy = ProtocolCompositionType::get(
563+
ctx, {keyPathTy, sendable->getDeclaredInterfaceType()},
564+
/*hasExplicitAnyObject=*/false);
565+
return ExistentialType::get(keyPathTy);
549566
}
567+
568+
return keyPathTy;
550569
}
551570

552571
void BindingSet::finalize(

lib/Sema/ConstraintSystem.cpp

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7445,6 +7445,7 @@ ConstraintSystem::inferKeyPathLiteralCapability(TypeVariableType *keyPathType) {
74457445
std::pair<bool, llvm::Optional<KeyPathCapability>>
74467446
ConstraintSystem::inferKeyPathLiteralCapability(KeyPathExpr *keyPath) {
74477447
bool didOptionalChain = false;
7448+
bool isSendable = true;
74487449

74497450
auto fail = []() -> std::pair<bool, llvm::Optional<KeyPathCapability>> {
74507451
return std::make_pair(false, llvm::None);
@@ -7454,9 +7455,9 @@ ConstraintSystem::inferKeyPathLiteralCapability(KeyPathExpr *keyPath) {
74547455
return std::make_pair(true, llvm::None);
74557456
};
74567457

7457-
auto success = [](KeyPathMutability mutability)
7458+
auto success = [](KeyPathMutability mutability, bool isSendable)
74587459
-> std::pair<bool, llvm::Optional<KeyPathCapability>> {
7459-
KeyPathCapability capability(mutability, /*isSendable=*/true);
7460+
KeyPathCapability capability(mutability, isSendable);
74607461
return std::make_pair(true, capability);
74617462
};
74627463

@@ -7475,10 +7476,33 @@ ConstraintSystem::inferKeyPathLiteralCapability(KeyPathExpr *keyPath) {
74757476
case KeyPathExpr::Component::Kind::CodeCompletion: {
74767477
return fail();
74777478
}
7479+
7480+
case KeyPathExpr::Component::Kind::UnresolvedSubscript:
7481+
case KeyPathExpr::Component::Kind::Subscript: {
7482+
if (Context.LangOpts.hasFeature(Feature::InferSendableFromCaptures)) {
7483+
// Key path is sendable only when all of its captures are sendable.
7484+
if (auto *args = component.getSubscriptArgs()) {
7485+
auto *sendable = Context.getProtocol(KnownProtocolKind::Sendable);
7486+
7487+
for (const auto &arg : *args) {
7488+
auto argTy = simplifyType(getType(arg.getExpr()));
7489+
7490+
// Sendability cannot be determined until the argument
7491+
// is fully resolved.
7492+
if (argTy->hasTypeVariable())
7493+
return delay();
7494+
7495+
auto conformance = lookupConformance(argTy, sendable);
7496+
isSendable &=
7497+
bool(conformance) &&
7498+
!conformance.hasMissingConformance(DC->getParentModule());
7499+
}
7500+
}
7501+
}
7502+
LLVM_FALLTHROUGH;
7503+
}
74787504
case KeyPathExpr::Component::Kind::Property:
7479-
case KeyPathExpr::Component::Kind::Subscript:
7480-
case KeyPathExpr::Component::Kind::UnresolvedProperty:
7481-
case KeyPathExpr::Component::Kind::UnresolvedSubscript: {
7505+
case KeyPathExpr::Component::Kind::UnresolvedProperty: {
74827506
auto *componentLoc =
74837507
getConstraintLocator(keyPath, LocatorPathElt::KeyPathComponent(i));
74847508
auto *calleeLoc = getCalleeLocator(componentLoc);
@@ -7555,7 +7579,7 @@ ConstraintSystem::inferKeyPathLiteralCapability(KeyPathExpr *keyPath) {
75557579
if (didOptionalChain)
75567580
mutability = KeyPathMutability::ReadOnly;
75577581

7558-
return success(mutability);
7582+
return success(mutability, isSendable);
75597583
}
75607584

75617585
TypeVarBindingProducer::TypeVarBindingProducer(BindingSet &bindings)

0 commit comments

Comments
 (0)