Skip to content

Commit 94e28b6

Browse files
committed
[Concurrency] InferSendableFromCaptures: Rework check to delay lookup
The current implementation of the check accounts only for the overload choices present in the initial lookup but for some situations, like bridged or optional base types, `performMemberLookup` uses a secondary lookup as well, results of which are ignored. Let's fold the check into `addChoice` instead and set the the flag there to make sure that all of the choices are considered. Resolves: rdar://143586718
1 parent 2e8f74f commit 94e28b6

File tree

2 files changed

+61
-52
lines changed

2 files changed

+61
-52
lines changed

lib/Sema/CSSimplify.cpp

Lines changed: 55 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -10278,6 +10278,55 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
1027810278
// have already been excluded.
1027910279
llvm::SmallPtrSet<ValueDecl *, 2> excludedDynamicMembers;
1028010280

10281+
// Delay solving member constraint for unapplied methods
10282+
// where the base type has a conditional Sendable conformance
10283+
auto shouldDelayDueToPartiallyResolvedBaseType =
10284+
[&](Type baseTy, ValueDecl *decl,
10285+
FunctionRefInfo functionRefInfo) -> bool {
10286+
if (!Context.LangOpts.hasFeature(Feature::InferSendableFromCaptures))
10287+
return false;
10288+
10289+
if (!Context.getProtocol(KnownProtocolKind::Sendable))
10290+
return false;
10291+
10292+
auto shouldCheckSendabilityOfBase = [&]() {
10293+
if (!isa_and_nonnull<FuncDecl>(decl))
10294+
return Type();
10295+
10296+
if (!decl->isInstanceMember() &&
10297+
!decl->getDeclContext()->getSelfProtocolDecl())
10298+
return Type();
10299+
10300+
auto hasAppliedSelf =
10301+
decl->hasCurriedSelf() && doesMemberRefApplyCurriedSelf(baseTy, decl);
10302+
auto numApplies = getNumApplications(hasAppliedSelf, functionRefInfo);
10303+
if (numApplies >= decl->getNumCurryLevels())
10304+
return Type();
10305+
10306+
return decl->isInstanceMember() ? baseTy->getMetatypeInstanceType()
10307+
: baseTy;
10308+
};
10309+
10310+
Type baseTyToCheck = shouldCheckSendabilityOfBase();
10311+
if (!baseTyToCheck)
10312+
return false;
10313+
10314+
auto sendableProtocol = Context.getProtocol(KnownProtocolKind::Sendable);
10315+
auto baseConformance = lookupConformance(baseTyToCheck, sendableProtocol);
10316+
10317+
return llvm::any_of(baseConformance.getConditionalRequirements(),
10318+
[&](const auto &req) {
10319+
if (req.getKind() != RequirementKind::Conformance)
10320+
return false;
10321+
10322+
return (req.getFirstType()->hasTypeVariable() &&
10323+
(req.getProtocolDecl()->isSpecificProtocol(
10324+
KnownProtocolKind::Sendable) ||
10325+
req.getProtocolDecl()->isSpecificProtocol(
10326+
KnownProtocolKind::SendableMetatype)));
10327+
});
10328+
};
10329+
1028110330
// Local function that adds the given declaration if it is a
1028210331
// reasonable choice.
1028310332
auto addChoice = [&](OverloadChoice candidate) {
@@ -10304,6 +10353,12 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
1030410353
auto baseTy = candidate.getBaseType();
1030510354
const auto baseObjTy = baseTy->getRValueType();
1030610355

10356+
// If we need to delay, update the status but record the member.
10357+
if (shouldDelayDueToPartiallyResolvedBaseType(
10358+
baseObjTy, decl, candidate.getFunctionRefInfo())) {
10359+
result.OverallResult = MemberLookupResult::Unsolved;
10360+
}
10361+
1030710362
bool hasInstanceMembers = false;
1030810363
bool hasInstanceMethods = false;
1030910364
bool hasStaticMembers = false;
@@ -10645,58 +10700,6 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
1064510700
return OverloadChoice(baseTy, cand, functionRefInfo);
1064610701
};
1064710702

10648-
// Delay solving member constraint for unapplied methods
10649-
// where the base type has a conditional Sendable conformance
10650-
if (Context.LangOpts.hasFeature(Feature::InferSendableFromCaptures)) {
10651-
auto shouldCheckSendabilityOfBase = [&]() {
10652-
if (!Context.getProtocol(KnownProtocolKind::Sendable))
10653-
return Type();
10654-
10655-
for (const auto &result : lookup) {
10656-
auto decl = result.getValueDecl();
10657-
if (!isa_and_nonnull<FuncDecl>(decl))
10658-
continue;
10659-
10660-
if (!decl->isInstanceMember() &&
10661-
!decl->getDeclContext()->getSelfProtocolDecl())
10662-
continue;
10663-
10664-
auto hasAppliedSelf = decl->hasCurriedSelf() &&
10665-
doesMemberRefApplyCurriedSelf(baseObjTy, decl);
10666-
auto numApplies = getNumApplications(hasAppliedSelf, functionRefInfo);
10667-
if (numApplies >= decl->getNumCurryLevels())
10668-
continue;
10669-
10670-
return decl->isInstanceMember()
10671-
? instanceTy
10672-
: MetatypeType::get(instanceTy);
10673-
}
10674-
10675-
return Type();
10676-
};
10677-
10678-
if (Type baseTyToCheck = shouldCheckSendabilityOfBase()) {
10679-
auto sendableProtocol = Context.getProtocol(KnownProtocolKind::Sendable);
10680-
auto baseConformance = lookupConformance(baseTyToCheck, sendableProtocol);
10681-
10682-
if (llvm::any_of(
10683-
baseConformance.getConditionalRequirements(),
10684-
[&](const auto &req) {
10685-
if (req.getKind() != RequirementKind::Conformance)
10686-
return false;
10687-
10688-
return (req.getFirstType()->hasTypeVariable() &&
10689-
(req.getProtocolDecl()->isSpecificProtocol(
10690-
KnownProtocolKind::Sendable) ||
10691-
req.getProtocolDecl()->isSpecificProtocol(
10692-
KnownProtocolKind::SendableMetatype)));
10693-
})) {
10694-
result.OverallResult = MemberLookupResult::Unsolved;
10695-
return result;
10696-
}
10697-
}
10698-
}
10699-
1070010703
// Add all results from this lookup.
1070110704
for (auto result : lookup)
1070210705
addChoice(getOverloadChoice(result.getValueDecl(),
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// RUN: %target-typecheck-verify-swift -swift-version 6
2+
3+
// rdar://143586718 - crash due to lookup not delayed on partially resolved base with Sendable requirements
4+
5+
_ = { () -> Array? in .max }
6+
// expected-error@-1 {{unable to infer closure type without a type annotation}}

0 commit comments

Comments
 (0)