mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[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
This commit is contained in:
@@ -10278,6 +10278,55 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
|
||||
// have already been excluded.
|
||||
llvm::SmallPtrSet<ValueDecl *, 2> excludedDynamicMembers;
|
||||
|
||||
// Delay solving member constraint for unapplied methods
|
||||
// where the base type has a conditional Sendable conformance
|
||||
auto shouldDelayDueToPartiallyResolvedBaseType =
|
||||
[&](Type baseTy, ValueDecl *decl,
|
||||
FunctionRefInfo functionRefInfo) -> bool {
|
||||
if (!Context.LangOpts.hasFeature(Feature::InferSendableFromCaptures))
|
||||
return false;
|
||||
|
||||
if (!Context.getProtocol(KnownProtocolKind::Sendable))
|
||||
return false;
|
||||
|
||||
auto shouldCheckSendabilityOfBase = [&]() {
|
||||
if (!isa_and_nonnull<FuncDecl>(decl))
|
||||
return Type();
|
||||
|
||||
if (!decl->isInstanceMember() &&
|
||||
!decl->getDeclContext()->getSelfProtocolDecl())
|
||||
return Type();
|
||||
|
||||
auto hasAppliedSelf =
|
||||
decl->hasCurriedSelf() && doesMemberRefApplyCurriedSelf(baseTy, decl);
|
||||
auto numApplies = getNumApplications(hasAppliedSelf, functionRefInfo);
|
||||
if (numApplies >= decl->getNumCurryLevels())
|
||||
return Type();
|
||||
|
||||
return decl->isInstanceMember() ? baseTy->getMetatypeInstanceType()
|
||||
: baseTy;
|
||||
};
|
||||
|
||||
Type baseTyToCheck = shouldCheckSendabilityOfBase();
|
||||
if (!baseTyToCheck)
|
||||
return false;
|
||||
|
||||
auto sendableProtocol = Context.getProtocol(KnownProtocolKind::Sendable);
|
||||
auto baseConformance = lookupConformance(baseTyToCheck, sendableProtocol);
|
||||
|
||||
return llvm::any_of(baseConformance.getConditionalRequirements(),
|
||||
[&](const auto &req) {
|
||||
if (req.getKind() != RequirementKind::Conformance)
|
||||
return false;
|
||||
|
||||
return (req.getFirstType()->hasTypeVariable() &&
|
||||
(req.getProtocolDecl()->isSpecificProtocol(
|
||||
KnownProtocolKind::Sendable) ||
|
||||
req.getProtocolDecl()->isSpecificProtocol(
|
||||
KnownProtocolKind::SendableMetatype)));
|
||||
});
|
||||
};
|
||||
|
||||
// Local function that adds the given declaration if it is a
|
||||
// reasonable choice.
|
||||
auto addChoice = [&](OverloadChoice candidate) {
|
||||
@@ -10304,6 +10353,12 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
|
||||
auto baseTy = candidate.getBaseType();
|
||||
const auto baseObjTy = baseTy->getRValueType();
|
||||
|
||||
// If we need to delay, update the status but record the member.
|
||||
if (shouldDelayDueToPartiallyResolvedBaseType(
|
||||
baseObjTy, decl, candidate.getFunctionRefInfo())) {
|
||||
result.OverallResult = MemberLookupResult::Unsolved;
|
||||
}
|
||||
|
||||
bool hasInstanceMembers = false;
|
||||
bool hasInstanceMethods = false;
|
||||
bool hasStaticMembers = false;
|
||||
@@ -10645,58 +10700,6 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
|
||||
return OverloadChoice(baseTy, cand, functionRefInfo);
|
||||
};
|
||||
|
||||
// Delay solving member constraint for unapplied methods
|
||||
// where the base type has a conditional Sendable conformance
|
||||
if (Context.LangOpts.hasFeature(Feature::InferSendableFromCaptures)) {
|
||||
auto shouldCheckSendabilityOfBase = [&]() {
|
||||
if (!Context.getProtocol(KnownProtocolKind::Sendable))
|
||||
return Type();
|
||||
|
||||
for (const auto &result : lookup) {
|
||||
auto decl = result.getValueDecl();
|
||||
if (!isa_and_nonnull<FuncDecl>(decl))
|
||||
continue;
|
||||
|
||||
if (!decl->isInstanceMember() &&
|
||||
!decl->getDeclContext()->getSelfProtocolDecl())
|
||||
continue;
|
||||
|
||||
auto hasAppliedSelf = decl->hasCurriedSelf() &&
|
||||
doesMemberRefApplyCurriedSelf(baseObjTy, decl);
|
||||
auto numApplies = getNumApplications(hasAppliedSelf, functionRefInfo);
|
||||
if (numApplies >= decl->getNumCurryLevels())
|
||||
continue;
|
||||
|
||||
return decl->isInstanceMember()
|
||||
? instanceTy
|
||||
: MetatypeType::get(instanceTy);
|
||||
}
|
||||
|
||||
return Type();
|
||||
};
|
||||
|
||||
if (Type baseTyToCheck = shouldCheckSendabilityOfBase()) {
|
||||
auto sendableProtocol = Context.getProtocol(KnownProtocolKind::Sendable);
|
||||
auto baseConformance = lookupConformance(baseTyToCheck, sendableProtocol);
|
||||
|
||||
if (llvm::any_of(
|
||||
baseConformance.getConditionalRequirements(),
|
||||
[&](const auto &req) {
|
||||
if (req.getKind() != RequirementKind::Conformance)
|
||||
return false;
|
||||
|
||||
return (req.getFirstType()->hasTypeVariable() &&
|
||||
(req.getProtocolDecl()->isSpecificProtocol(
|
||||
KnownProtocolKind::Sendable) ||
|
||||
req.getProtocolDecl()->isSpecificProtocol(
|
||||
KnownProtocolKind::SendableMetatype)));
|
||||
})) {
|
||||
result.OverallResult = MemberLookupResult::Unsolved;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add all results from this lookup.
|
||||
for (auto result : lookup)
|
||||
addChoice(getOverloadChoice(result.getValueDecl(),
|
||||
|
||||
Reference in New Issue
Block a user