Skip to content

Commit bd313de

Browse files
authored
Merge pull request #76136 from xedin/rdar-131321053
[ConstraintSystem] InferSendableFromCaptures: Mark unapplied operator references as `@Sendable`
2 parents 39b8b3c + daab4e1 commit bd313de

File tree

5 files changed

+81
-45
lines changed

5 files changed

+81
-45
lines changed

include/swift/Sema/ConstraintSystem.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5605,8 +5605,6 @@ class ConstraintSystem {
56055605
return range.isValid() ? range : std::optional<SourceRange>();
56065606
}
56075607

5608-
bool isPartialApplication(ConstraintLocator *locator);
5609-
56105608
bool isTooComplex(size_t solutionMemory) {
56115609
if (isAlreadyTooComplex.first)
56125610
return true;
@@ -6554,6 +6552,11 @@ Type getPatternTypeOfSingleUnlabeledPackExpansionTuple(Type type);
65546552
/// Check whether this is a reference to one of the special result builder
65556553
/// methods prefixed with `build*` i.e. `buildBlock`, `buildExpression` etc.
65566554
bool isResultBuilderMethodReference(ASTContext &, UnresolvedDotExpr *);
6555+
6556+
/// Determine the number of applications applied to the given overload.
6557+
unsigned getNumApplications(ValueDecl *decl, bool hasAppliedSelf,
6558+
FunctionRefKind functionRefKind);
6559+
65576560
} // end namespace constraints
65586561

65596562
template<typename ...Args>

lib/Sema/CSGen.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4607,13 +4607,14 @@ generateForEachStmtConstraints(ConstraintSystem &cs, DeclContext *dc,
46074607
new (ctx) DeclRefExpr(makeIteratorVar, DeclNameLoc(stmt->getForLoc()),
46084608
/*Implicit=*/true),
46094609
nextId, labels);
4610-
nextRef->setFunctionRefKind(FunctionRefKind::Compound);
4610+
nextRef->setFunctionRefKind(FunctionRefKind::SingleApply);
46114611

46124612
ArgumentList *nextArgs;
46134613
if (nextFn && nextFn->getParameters()->size() == 1) {
46144614
auto isolationArg =
46154615
new (ctx) CurrentContextIsolationExpr(stmt->getForLoc(), Type());
4616-
nextArgs = ArgumentList::forImplicitUnlabeled(ctx, { isolationArg });
4616+
nextArgs = ArgumentList::createImplicit(
4617+
ctx, {Argument(SourceLoc(), ctx.Id_isolation, isolationArg)});
46174618
} else {
46184619
nextArgs = ArgumentList::createImplicit(ctx, {});
46194620
}

lib/Sema/CSSimplify.cpp

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10293,15 +10293,16 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
1029310293
if (!Context.getProtocol(KnownProtocolKind::Sendable))
1029410294
return false;
1029510295

10296-
// Static members are always sendable because they only capture
10297-
// metatypes which are Sendable.
10298-
if (baseObjTy->is<AnyMetatypeType>())
10299-
return false;
10296+
return llvm::any_of(lookup, [&](const auto &result) {
10297+
auto decl = result.getValueDecl();
10298+
if (!isa_and_nonnull<FuncDecl>(decl))
10299+
return false;
1030010300

10301-
return isPartialApplication(memberLocator) &&
10302-
llvm::any_of(lookup, [&](const auto &result) {
10303-
return isa_and_nonnull<FuncDecl>(result.getValueDecl());
10304-
});
10301+
auto hasAppliedSelf = decl->hasCurriedSelf() &&
10302+
doesMemberRefApplyCurriedSelf(baseObjTy, decl);
10303+
return getNumApplications(decl, hasAppliedSelf, functionRefKind) <
10304+
decl->getNumCurryLevels();
10305+
});
1030510306
};
1030610307

1030710308
if (shouldCheckSendabilityOfBase()) {
@@ -10945,7 +10946,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint(
1094510946

1094610947
return simplifyValueWitnessConstraint(
1094710948
ConstraintKind::ValueWitness, baseTy, makeIterator, memberTy, useDC,
10948-
FunctionRefKind::Compound, flags, locator);
10949+
FunctionRefKind::SingleApply, flags, locator);
1094910950
}
1095010951

1095110952
// Handle `next` reference.
@@ -10963,7 +10964,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint(
1096310964

1096410965
return simplifyValueWitnessConstraint(
1096510966
ConstraintKind::ValueWitness, baseTy, next, memberTy, useDC,
10966-
FunctionRefKind::Compound, flags, locator);
10967+
FunctionRefKind::SingleApply, flags, locator);
1096710968
}
1096810969
}
1096910970
}

lib/Sema/ConstraintSystem.cpp

Lines changed: 29 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1655,8 +1655,8 @@ static unsigned getNumRemovedArgumentLabels(ValueDecl *decl,
16551655
}
16561656

16571657
/// Determine the number of applications
1658-
static unsigned getNumApplications(
1659-
ValueDecl *decl, bool hasAppliedSelf, FunctionRefKind functionRefKind) {
1658+
unsigned constraints::getNumApplications(ValueDecl *decl, bool hasAppliedSelf,
1659+
FunctionRefKind functionRefKind) {
16601660
switch (functionRefKind) {
16611661
case FunctionRefKind::Unapplied:
16621662
case FunctionRefKind::Compound:
@@ -1774,18 +1774,36 @@ FunctionType *ConstraintSystem::adjustFunctionTypeForConcurrency(
17741774
adjustedTy =
17751775
adjustedTy->withExtInfo(adjustedTy->getExtInfo().withSendable());
17761776
}
1777-
} else if (isPartialApplication(getConstraintLocator(locator))) {
1778-
if (baseType &&
1779-
(baseType->is<AnyMetatypeType>() || baseType->isSendableType())) {
1780-
auto referenceTy = adjustedTy->getResult()->castTo<FunctionType>();
1777+
} else if (numApplies < decl->getNumCurryLevels() &&
1778+
decl->hasCurriedSelf() ) {
1779+
auto shouldMarkMemberTypeSendable = [&]() {
1780+
// Static member types are @Sendable on both levels because
1781+
// they only capture a metatype "base" that is always Sendable.
1782+
// For example, `(S.Type) -> () -> Void`.
1783+
if (!decl->isInstanceMember())
1784+
return true;
1785+
1786+
// For instance members we need to check whether instance type
1787+
// is Sendable because @Sendable function values cannot capture
1788+
// non-Sendable values (base instance type in this case).
1789+
// For example, `(C) -> () -> Void` where `C` should be Sendable
1790+
// for the inner function type to be Sendable as well.
1791+
return baseType &&
1792+
baseType->getMetatypeInstanceType()->isSendableType();
1793+
};
1794+
1795+
auto referenceTy = adjustedTy->getResult()->castTo<FunctionType>();
1796+
if (shouldMarkMemberTypeSendable()) {
17811797
referenceTy =
1782-
referenceTy->withExtInfo(referenceTy->getExtInfo().withSendable())
1798+
referenceTy
1799+
->withExtInfo(referenceTy->getExtInfo().withSendable())
17831800
->getAs<FunctionType>();
1784-
1785-
adjustedTy =
1786-
FunctionType::get(adjustedTy->getParams(), referenceTy,
1787-
adjustedTy->getExtInfo().withSendable());
17881801
}
1802+
1803+
// @Sendable since fully uncurried type doesn't capture anything.
1804+
adjustedTy =
1805+
FunctionType::get(adjustedTy->getParams(), referenceTy,
1806+
adjustedTy->getExtInfo().withSendable());
17891807
}
17901808
}
17911809
}
@@ -2636,26 +2654,6 @@ static unsigned getApplicationLevel(ConstraintSystem &CS, Type baseTy,
26362654
return level;
26372655
}
26382656

2639-
bool ConstraintSystem::isPartialApplication(ConstraintLocator *locator) {
2640-
// If this is a compiler synthesized implicit conversion, let's skip
2641-
// the check because the base of `UDE` is not the base of the injected
2642-
// initializer.
2643-
if (locator->isLastElement<LocatorPathElt::ConstructorMember>() &&
2644-
locator->findFirst<LocatorPathElt::ImplicitConversion>())
2645-
return false;
2646-
2647-
auto *UDE = getAsExpr<UnresolvedDotExpr>(locator->getAnchor());
2648-
if (UDE == nullptr)
2649-
return false;
2650-
2651-
auto baseTy =
2652-
simplifyType(getType(UDE->getBase()))->getWithoutSpecifierType();
2653-
auto level = getApplicationLevel(*this, baseTy, UDE);
2654-
// Static members have base applied implicitly which means that their
2655-
// application level is lower.
2656-
return level < (baseTy->is<MetatypeType>() ? 1 : 2);
2657-
}
2658-
26592657
bool IsInLeftHandSideOfAssignment::operator()(Expr *expr) const {
26602658
// Walk up the parent tree.
26612659
auto parent = cs.getParentExpr(expr);

test/Concurrency/sendable_methods.swift

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,3 +286,36 @@ func testPatternMatch(ge: [GenericE<Int>]) {
286286
_ = a
287287
}
288288
}
289+
290+
// rdar://131321053 - cannot pass an operator to parameter that expectes a @Sendable type
291+
do {
292+
func test(_: @Sendable (Int, Int) -> Bool) {
293+
}
294+
295+
test(<) // Ok
296+
}
297+
298+
// Partially applied instance method
299+
do {
300+
struct S {
301+
func foo() {}
302+
}
303+
304+
func bar(_ x: @Sendable () -> Void) {}
305+
306+
let fn = S.foo(S())
307+
bar(fn) // Ok
308+
309+
let _: @Sendable (S) -> @Sendable () -> Void = S.foo // Ok
310+
311+
let classFn = NonSendable.f(NonSendable())
312+
bar(classFn) // expected-warning {{converting non-sendable function value to '@Sendable () -> Void' may introduce data races}}
313+
314+
let _: @Sendable (NonSendable) -> () -> Void = NonSendable.f // Ok
315+
316+
class Test {
317+
static func staticFn() {}
318+
}
319+
320+
bar(Test.staticFn) // Ok
321+
}

0 commit comments

Comments
 (0)