Skip to content

Commit 9e408af

Browse files
committed
[Sema] Global funcs should always be Sendable
Global funcs should be Sendable by default because they don't capture anything.
1 parent 4028f15 commit 9e408af

File tree

5 files changed

+45
-21
lines changed

5 files changed

+45
-21
lines changed

lib/Sema/CSSimplify.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9521,7 +9521,7 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
95219521

95229522
// Delay solving member constraint for unapplied methods
95239523
// where the base type has a conditional Sendable conformance
9524-
if (functionRefKind == FunctionRefKind::Unapplied){
9524+
if (functionRefKind == FunctionRefKind::Unapplied) {
95259525
auto sendableProtocol = DC->getParentModule()->getASTContext().getProtocol(KnownProtocolKind::Sendable);
95269526
auto baseSendable = swift::TypeChecker::conformsToProtocol(instanceTy, sendableProtocol, DC->getParentModule());
95279527

lib/Sema/ConstraintSystem.cpp

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1160,7 +1160,6 @@ FunctionType *ConstraintSystem::openFunctionType(
11601160
DeclContext *outerDC) {
11611161
if (auto *genericFn = funcType->getAs<GenericFunctionType>()) {
11621162
auto signature = genericFn->getGenericSignature();
1163-
//TO-DO Maybe update here
11641163
openGenericParameters(outerDC, signature, replacements, locator);
11651164

11661165
openGenericRequirements(outerDC, signature,
@@ -1672,7 +1671,6 @@ ConstraintSystem::getTypeOfReference(ValueDecl *value,
16721671

16731672
OpenedTypeMap replacements;
16741673

1675-
// TO-DO check for sendable here and update type
16761674
AnyFunctionType *funcType = func->getInterfaceType()
16771675
->castTo<AnyFunctionType>();
16781676
auto openedType = openFunctionType(
@@ -1712,8 +1710,6 @@ ConstraintSystem::getTypeOfReference(ValueDecl *value,
17121710
auto numLabelsToRemove = getNumRemovedArgumentLabels(
17131711
funcDecl, /*isCurriedInstanceReference=*/false, functionRefKind);
17141712

1715-
//funcType = funcType->withExtInfo(functy->getExtInfo().withConcurrent())->castTo<AnyFunctionType>();
1716-
17171713
auto openedType = openFunctionType(funcType, locator, replacements,
17181714
funcDecl->getDeclContext())
17191715
->removeArgumentLabels(numLabelsToRemove);
@@ -2628,13 +2624,14 @@ ConstraintSystem::getTypeOfMemberReference(
26282624
functionType = unwrapPropertyWrapperParameterTypes(*this, funcDecl, functionRefKind,
26292625
functionType, locator);
26302626
auto sendableProtocol = useDC->getParentModule()->getASTContext().getProtocol(KnownProtocolKind::Sendable);
2631-
// FIXME: Handle conditional conformances
26322627
auto baseSendable = TypeChecker::conformsToProtocol( baseOpenedTy, sendableProtocol, useDC->getParentModule());
2633-
2628+
26342629
if (isSendableType(useDC->getParentModule(), baseOpenedTy)) {
26352630
if (baseSendable.getConditionalRequirements().empty())
2631+
//Functions w/o conditional conformances should be marked @Sendable
26362632
functionType = functionType->withExtInfo(functionType->getExtInfo().withConcurrent())->getAs<FunctionType>();
26372633

2634+
// Handle Conditional Conformances
26382635
for (auto req : baseSendable.getConditionalRequirements()){
26392636
if(!TypeChecker::conformsToProtocol( req.getFirstType(), sendableProtocol, useDC->getParentModule()).isInvalid()){
26402637
functionType = functionType->withExtInfo(functionType->getExtInfo().withConcurrent())->getAs<FunctionType>();
@@ -2646,6 +2643,12 @@ ConstraintSystem::getTypeOfMemberReference(
26462643
FunctionType::ExtInfo info;
26472644
openedType =
26482645
FunctionType::get(fullFunctionType->getParams(), functionType, info);
2646+
2647+
if (isSendableType(useDC->getParentModule(), baseOpenedTy)) {
2648+
// If this is actually a Sendable type, implicitly mark @Sendable
2649+
auto origFnType = openedType->castTo<FunctionType>();
2650+
openedType = origFnType->withExtInfo(origFnType->getExtInfo().withConcurrent());
2651+
}
26492652
}
26502653

26512654
// Adjust the opened type for concurrency.

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5480,6 +5480,15 @@ AnyFunctionType *swift::adjustFunctionTypeForConcurrency(
54805480
// Apply unsafe concurrency features to the given function type.
54815481
bool strictChecking = contextRequiresStrictConcurrencyChecking(
54825482
dc, getType, isolatedByPreconcurrency);
5483+
5484+
auto func = dyn_cast_or_null<AbstractFunctionDecl>(decl);
5485+
auto doesNotCapture = func->getCaptureInfo().getCaptures().empty();
5486+
5487+
if (doesNotCapture) {
5488+
fnType = fnType->withExtInfo(fnType->getExtInfo().withConcurrent());
5489+
return fnType;
5490+
}
5491+
54835492
fnType = applyUnsafeConcurrencyToFunctionType(
54845493
fnType, decl, strictChecking, numApplies, isMainDispatchQueue);
54855494

test/Concurrency/sendable_functions.swift

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,3 @@ extension S: Sendable where T: Sendable {
4646

4747
@available(SwiftStdlib 5.1, *)
4848
@MainActor @Sendable func globalActorFuncAsync() async { }
49-
50-
func doWork() -> Int {
51-
Int.random(in: 1..<42)
52-
}
53-
54-
// unapplied global func call
55-
let work: @Sendable () -> Int = doWork
56-
Task<Int, Never>.detached(priority: nil, operation: doWork)
57-
Task<Int, Never>.detached(priority: nil, operation: work)

test/Concurrency/sendable_methods.swift

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,10 @@ g(InferredSendableE.f)
7777
g(GenericS<Int>.f)
7878
g(GenericC<Int>.f)
7979

80-
g(GenericS<NonSendable>.f)
81-
g(GenericC<NonSendable>.f)
80+
g(GenericS<NonSendable>.f) // expected-warning{{converting non-sendable function value to '@Sendable (GenericS<NonSendable>) -> (@Sendable () -> Void)' may introduce data races
81+
// expected-warning{{converting non-sendable function value to '@Sendable () -> Void' may introduce data races
82+
g(GenericC<NonSendable>.f) // expected-warning{{converting non-sendable function value to '@Sendable (GenericS<NonSendable>) -> (@Sendable () -> Void)' may introduce data races
83+
// expected-warning{{converting non-sendable function value to '@Sendable () -> Void' may introduce data races
8284

8385
func executeAsTask (_ f: @escaping @Sendable () -> Void) {
8486
Task {
@@ -90,6 +92,7 @@ func executeAsTask (_ f: @escaping @Sendable () -> Void) {
9092
executeAsTask(C().f)
9193
executeAsTask(S().f)
9294
executeAsTask(E().f)
95+
executeAsTask(NonSendable().f) // expected-warning{{converting non-sendable function value to '@Sendable () -> Void' may introduce data races}}
9396

9497
// Declarations
9598
let us: @Sendable (GenericS<Int>) -> (@Sendable () -> Void) = GenericS<Int>.f
@@ -104,13 +107,31 @@ var partialClass : @Sendable () -> Void = C().f
104107
var partialEnum : @Sendable () -> Void = E().f
105108

106109
// Reassign
107-
partialClass = NonSendable().f
108-
partialStruct = NonSendable().f
109-
partialEnum = NonSendable().f
110+
partialClass = NonSendable().f // expected-warning{{converting non-sendable function value to '@Sendable () -> Void' may introduce data races}}
111+
partialStruct = NonSendable().f // expected-warning{{converting non-sendable function value to '@Sendable () -> Void' may introduce data races}}
112+
partialEnum = NonSendable().f // expected-warning{{converting non-sendable function value to '@Sendable () -> Void' may introduce data races}}
110113

111114
// Static Functions
112115
struct World {
113116
static func greet () { print("hello") }
114117
}
115118

116119
let helloworld: @Sendable () -> Void = World.greet
120+
121+
class NonSendableC {
122+
var x: Int = 0
123+
124+
// TO-DO: Invalidate Sendable annotation in follow-up PR
125+
@Sendable func inc() {
126+
x += 1
127+
}
128+
}
129+
130+
func doWork() -> Int {
131+
Int.random(in: 1..<42)
132+
}
133+
134+
// unapplied global func call
135+
let work: @Sendable () -> Int = doWork
136+
Task<Int, Never>.detached(priority: nil, operation: doWork)
137+
Task<Int, Never>.detached(priority: nil, operation: work)

0 commit comments

Comments
 (0)