Skip to content

Commit daab4e1

Browse files
committed
[ConstraintSystem] InferSenableFromCaptures: Fix treatment of partially applied instance methods on non-Sendable base
In situations like: ``` class A { func test() {} } ``` Fully uncurried function type should be @sendable but inner method cannot be because it captures a non-Sendable type `A` when applied.
1 parent df27db1 commit daab4e1

File tree

2 files changed

+40
-12
lines changed

2 files changed

+40
-12
lines changed

lib/Sema/ConstraintSystem.cpp

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1774,21 +1774,36 @@ FunctionType *ConstraintSystem::adjustFunctionTypeForConcurrency(
17741774
adjustedTy =
17751775
adjustedTy->withExtInfo(adjustedTy->getExtInfo().withSendable());
17761776
}
1777-
} else if (numApplies < decl->getNumCurryLevels()) {
1778-
// Operators on protocols could be found via unqualified lookup and
1779-
// won't have a base type.
1780-
if (decl->isOperator() ||
1781-
(baseType &&
1782-
(baseType->is<AnyMetatypeType>() || baseType->isSendableType()))) {
1783-
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()) {
17841797
referenceTy =
1785-
referenceTy->withExtInfo(referenceTy->getExtInfo().withSendable())
1798+
referenceTy
1799+
->withExtInfo(referenceTy->getExtInfo().withSendable())
17861800
->getAs<FunctionType>();
1787-
1788-
adjustedTy =
1789-
FunctionType::get(adjustedTy->getParams(), referenceTy,
1790-
adjustedTy->getExtInfo().withSendable());
17911801
}
1802+
1803+
// @Sendable since fully uncurried type doesn't capture anything.
1804+
adjustedTy =
1805+
FunctionType::get(adjustedTy->getParams(), referenceTy,
1806+
adjustedTy->getExtInfo().withSendable());
17921807
}
17931808
}
17941809
}

test/Concurrency/sendable_methods.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,4 +305,17 @@ do {
305305

306306
let fn = S.foo(S())
307307
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
308321
}

0 commit comments

Comments
 (0)