Skip to content

Commit 29cade6

Browse files
authored
Merge pull request #72741 from xedin/rdar-119593407-6.0
[6.0][TypeChecker] InferSendableFromCaptures: Infer @sendable on adjusted types
2 parents e2696ad + 9d0e019 commit 29cade6

File tree

5 files changed

+95
-65
lines changed

5 files changed

+95
-65
lines changed

include/swift/Sema/ConstraintSystem.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4370,8 +4370,8 @@ class ConstraintSystem {
43704370

43714371
/// Wrapper over swift::adjustFunctionTypeForConcurrency that passes along
43724372
/// the appropriate closure-type and opening extraction functions.
4373-
AnyFunctionType *adjustFunctionTypeForConcurrency(
4374-
AnyFunctionType *fnType, ValueDecl *decl, DeclContext *dc,
4373+
FunctionType *adjustFunctionTypeForConcurrency(
4374+
FunctionType *fnType, Type baseType, ValueDecl *decl, DeclContext *dc,
43754375
unsigned numApplies, bool isMainDispatchQueue,
43764376
OpenedTypeMap &replacements, ConstraintLocatorBuilder locator);
43774377

lib/Sema/ConstraintSystem.cpp

Lines changed: 46 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1695,20 +1695,46 @@ static bool isRequirementOrWitness(const ConstraintLocatorBuilder &locator) {
16951695
locator.endsWith<LocatorPathElt::Witness>();
16961696
}
16971697

1698-
AnyFunctionType *ConstraintSystem::adjustFunctionTypeForConcurrency(
1699-
AnyFunctionType *fnType, ValueDecl *decl, DeclContext *dc,
1698+
FunctionType *ConstraintSystem::adjustFunctionTypeForConcurrency(
1699+
FunctionType *fnType, Type baseType, ValueDecl *decl, DeclContext *dc,
17001700
unsigned numApplies, bool isMainDispatchQueue, OpenedTypeMap &replacements,
17011701
ConstraintLocatorBuilder locator) {
17021702

1703-
return swift::adjustFunctionTypeForConcurrency(
1704-
fnType, decl, dc, numApplies, isMainDispatchQueue,
1705-
GetClosureType{*this}, ClosureIsolatedByPreconcurrency{*this},
1706-
[&](Type type) {
1703+
auto *adjustedTy = swift::adjustFunctionTypeForConcurrency(
1704+
fnType, decl, dc, numApplies, isMainDispatchQueue, GetClosureType{*this},
1705+
ClosureIsolatedByPreconcurrency{*this}, [&](Type type) {
17071706
if (replacements.empty())
17081707
return type;
17091708

17101709
return openType(type, replacements, locator);
17111710
});
1711+
1712+
if (Context.LangOpts.hasFeature(Feature::InferSendableFromCaptures)) {
1713+
if (auto *FD = dyn_cast<AbstractFunctionDecl>(decl)) {
1714+
auto *DC = FD->getDeclContext();
1715+
// All global functions should be @Sendable
1716+
if (DC->isModuleScopeContext()) {
1717+
if (!adjustedTy->getExtInfo().isSendable()) {
1718+
adjustedTy =
1719+
adjustedTy->withExtInfo(adjustedTy->getExtInfo().withSendable());
1720+
}
1721+
} else if (isPartialApplication(getConstraintLocator(locator))) {
1722+
if (baseType &&
1723+
(baseType->is<AnyMetatypeType>() || baseType->isSendableType())) {
1724+
auto referenceTy = adjustedTy->getResult()->castTo<FunctionType>();
1725+
referenceTy =
1726+
referenceTy->withExtInfo(referenceTy->getExtInfo().withSendable())
1727+
->getAs<FunctionType>();
1728+
1729+
adjustedTy =
1730+
FunctionType::get(adjustedTy->getParams(), referenceTy,
1731+
adjustedTy->getExtInfo().withSendable());
1732+
}
1733+
}
1734+
}
1735+
}
1736+
1737+
return adjustedTy->castTo<FunctionType>();
17121738
}
17131739

17141740
/// For every parameter in \p type that has an error type, replace that
@@ -1781,9 +1807,9 @@ ConstraintSystem::getTypeOfReference(ValueDecl *value,
17811807
auto origOpenedType = openedType;
17821808
if (!isRequirementOrWitness(locator)) {
17831809
unsigned numApplies = getNumApplications(value, false, functionRefKind);
1784-
openedType = cast<FunctionType>(adjustFunctionTypeForConcurrency(
1785-
origOpenedType, func, useDC, numApplies, false, replacements,
1786-
locator));
1810+
openedType = adjustFunctionTypeForConcurrency(
1811+
origOpenedType, /*baseType=*/Type(), func, useDC, numApplies, false,
1812+
replacements, locator);
17871813
}
17881814

17891815
// The reference implicitly binds 'self'.
@@ -1799,14 +1825,6 @@ ConstraintSystem::getTypeOfReference(ValueDecl *value,
17991825
auto numLabelsToRemove = getNumRemovedArgumentLabels(
18001826
funcDecl, /*isCurriedInstanceReference=*/false, functionRefKind);
18011827

1802-
if (Context.LangOpts.hasFeature(Feature::InferSendableFromCaptures)) {
1803-
// All global functions should be @Sendable
1804-
if (funcDecl->getDeclContext()->isModuleScopeContext()) {
1805-
funcType =
1806-
funcType->withExtInfo(funcType->getExtInfo().withSendable());
1807-
}
1808-
}
1809-
18101828
auto openedType = openFunctionType(funcType, locator, replacements,
18111829
funcDecl->getDeclContext())
18121830
->removeArgumentLabels(numLabelsToRemove);
@@ -1818,9 +1836,9 @@ ConstraintSystem::getTypeOfReference(ValueDecl *value,
18181836
if (!isRequirementOrWitness(locator)) {
18191837
unsigned numApplies = getNumApplications(
18201838
funcDecl, false, functionRefKind);
1821-
openedType = cast<FunctionType>(adjustFunctionTypeForConcurrency(
1822-
origOpenedType->castTo<FunctionType>(), funcDecl, useDC, numApplies,
1823-
false, replacements, locator));
1839+
openedType = adjustFunctionTypeForConcurrency(
1840+
origOpenedType->castTo<FunctionType>(), /*baseType=*/Type(), funcDecl,
1841+
useDC, numApplies, false, replacements, locator);
18241842
}
18251843

18261844
if (isForCodeCompletion() && openedType->hasError()) {
@@ -2788,20 +2806,6 @@ ConstraintSystem::getTypeOfMemberReference(
27882806
// FIXME: Verify ExtInfo state is correct, not working by accident.
27892807
FunctionType::ExtInfo info;
27902808

2791-
if (Context.LangOpts.hasFeature(Feature::InferSendableFromCaptures)) {
2792-
if (isPartialApplication(locator) &&
2793-
(resolvedBaseTy->is<AnyMetatypeType>() ||
2794-
baseOpenedTy->isSendableType())) {
2795-
// Add @Sendable to functions without conditional conformances
2796-
functionType =
2797-
functionType
2798-
->withExtInfo(functionType->getExtInfo().withSendable())
2799-
->getAs<FunctionType>();
2800-
}
2801-
// Unapplied values should always be Sendable
2802-
info = info.withSendable();
2803-
}
2804-
28052809
// We'll do other adjustment later, but we need to handle parameter
28062810
// isolation to avoid assertions.
28072811
if (fullFunctionType->getIsolation().isParameter())
@@ -2819,11 +2823,12 @@ ConstraintSystem::getTypeOfMemberReference(
28192823
unsigned numApplies = getNumApplications(
28202824
value, hasAppliedSelf, functionRefKind);
28212825
openedType = adjustFunctionTypeForConcurrency(
2822-
origOpenedType->castTo<AnyFunctionType>(), value, useDC, numApplies,
2823-
isMainDispatchQueueMember(locator), replacements, locator);
2826+
origOpenedType->castTo<FunctionType>(), resolvedBaseTy, value, useDC,
2827+
numApplies, isMainDispatchQueueMember(locator), replacements, locator);
28242828
} else if (auto subscript = dyn_cast<SubscriptDecl>(value)) {
28252829
openedType = adjustFunctionTypeForConcurrency(
2826-
origOpenedType->castTo<AnyFunctionType>(), subscript, useDC,
2830+
origOpenedType->castTo<FunctionType>(), resolvedBaseTy, subscript,
2831+
useDC,
28272832
/*numApplies=*/2, /*isMainDispatchQueue=*/false, replacements, locator);
28282833
} else if (auto var = dyn_cast<VarDecl>(value)) {
28292834
// Adjust the function's result type, since that's the Var's actual type.
@@ -2952,7 +2957,8 @@ Type ConstraintSystem::getEffectiveOverloadType(ConstraintLocator *locator,
29522957
// FIXME: Verify ExtInfo state is correct, not working by accident.
29532958
FunctionType::ExtInfo info;
29542959
type = adjustFunctionTypeForConcurrency(
2955-
FunctionType::get(indices, elementTy, info), subscript, useDC,
2960+
FunctionType::get(indices, elementTy, info), overload.getBaseType(),
2961+
subscript, useDC,
29562962
/*numApplies=*/1, /*isMainDispatchQueue=*/false, emptyReplacements,
29572963
locator);
29582964
} else if (auto var = dyn_cast<VarDecl>(decl)) {
@@ -3000,7 +3006,8 @@ Type ConstraintSystem::getEffectiveOverloadType(ConstraintLocator *locator,
30003006
decl, hasAppliedSelf, overload.getFunctionRefKind());
30013007

30023008
type = adjustFunctionTypeForConcurrency(
3003-
type->castTo<FunctionType>(), decl, useDC, numApplies,
3009+
type->castTo<FunctionType>(), overload.getBaseType(), decl,
3010+
useDC, numApplies,
30043011
/*isMainDispatchQueue=*/false, emptyReplacements, locator)
30053012
->getResult();
30063013
}

lib/Sema/MiscDiagnostics.cpp

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,8 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC,
257257
// Void to _ then warn, because that is redundant.
258258
if (auto DAE = dyn_cast<DiscardAssignmentExpr>(destExpr)) {
259259
if (auto CE = dyn_cast<CallExpr>(AE->getSrc())) {
260-
if (isa_and_nonnull<FuncDecl>(CE->getCalledValue()) &&
260+
if (getAsDecl<FuncDecl>(
261+
CE->getCalledValue(/*skipFunctionConversions=*/true)) &&
261262
CE->getType()->isVoid()) {
262263
Ctx.Diags
263264
.diagnose(DAE->getLoc(),
@@ -311,7 +312,7 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC,
311312
// FIXME: Duplicate labels on enum payloads should be diagnosed
312313
// when declared, not when called.
313314
if (auto *CE = dyn_cast_or_null<CallExpr>(E)) {
314-
auto calledValue = CE->getCalledValue();
315+
auto calledValue = CE->getCalledValue(/*skipFunctionConversions=*/true);
315316
if (calledValue && isa<EnumElementDecl>(calledValue)) {
316317
auto *args = CE->getArgs();
317318
SmallVector<Identifier, 4> scratch;
@@ -1464,6 +1465,9 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC,
14641465
if (auto dotSyntax = dyn_cast<DotSyntaxCallExpr>(fnExpr))
14651466
fnExpr = dotSyntax->getSemanticFn();
14661467

1468+
if (auto *FCE = dyn_cast<FunctionConversionExpr>(fnExpr))
1469+
fnExpr = FCE->getSubExpr();
1470+
14671471
auto DRE = dyn_cast<DeclRefExpr>(fnExpr);
14681472
if (!DRE || !DRE->getDecl()->isOperator())
14691473
return;
@@ -5093,7 +5097,7 @@ static void diagnoseUnintendedOptionalBehavior(const Expr *E,
50935097
return declRef->getDecl();
50945098

50955099
if (auto *apply = dyn_cast<ApplyExpr>(E)) {
5096-
auto *decl = apply->getCalledValue();
5100+
auto *decl = apply->getCalledValue(/*skipFunctionConversions=*/true);
50975101
if (isa_and_nonnull<AbstractFunctionDecl>(decl))
50985102
return decl;
50995103
}
@@ -5232,9 +5236,10 @@ static void diagnoseUnintendedOptionalBehavior(const Expr *E,
52325236

52335237
void diagnoseIfUnintendedInterpolation(CallExpr *segment,
52345238
UnintendedInterpolationKind kind) {
5235-
if (interpolationWouldBeUnintended(segment->getCalledValue(), kind))
5239+
if (interpolationWouldBeUnintended(
5240+
segment->getCalledValue(/*skipFunctionConversions=*/true), kind))
52365241
if (auto firstArg =
5237-
getFirstArgIfUnintendedInterpolation(segment->getArgs(), kind))
5242+
getFirstArgIfUnintendedInterpolation(segment->getArgs(), kind))
52385243
diagnoseUnintendedInterpolation(firstArg, kind);
52395244
}
52405245

@@ -5445,7 +5450,7 @@ static void maybeDiagnoseCallToKeyValueObserveMethod(const Expr *E,
54455450
KVOObserveCallWalker(ASTContext &ctx) : C(ctx) {}
54465451

54475452
void maybeDiagnoseCallExpr(CallExpr *expr) {
5448-
auto fn = expr->getCalledValue();
5453+
auto fn = expr->getCalledValue(/*skipFunctionConversions=*/true);
54495454
if (!fn)
54505455
return;
54515456
SmallVector<KeyPathExpr *, 1> keyPathArgs;
@@ -5583,9 +5588,10 @@ static void diagnoseComparisonWithNaN(const Expr *E, const DeclContext *DC) {
55835588
// Dig out the function declaration.
55845589
if (auto Fn = BE->getFn()) {
55855590
if (auto DSCE = dyn_cast<DotSyntaxCallExpr>(Fn)) {
5586-
comparisonDecl = DSCE->getCalledValue();
5591+
comparisonDecl =
5592+
DSCE->getCalledValue(/*skipFunctionConversions=*/true);
55875593
} else {
5588-
comparisonDecl = BE->getCalledValue();
5594+
comparisonDecl = BE->getCalledValue(/*skipFunctionConversions=*/true);
55895595
}
55905596
}
55915597

test/Concurrency/sendable_functions.swift

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

4747
@available(SwiftStdlib 5.1, *)
4848
@MainActor @Sendable func globalActorFuncAsync() async { }
49-
50-
func test_initializer_ref() {
51-
func test<T>(_: @Sendable (T, T) -> Array<T>) {
52-
}
53-
54-
// Type of `initRef` should be @Sendable but due to implicitly injected autoclosure it isn't
55-
let initRef = Array.init as (Int, Int) -> Array<Int>
56-
57-
// FIXME: incorrect non-Sendable diagnostic is produced due to `autoclosure` wrapping `Array.init`
58-
test(initRef)
59-
// expected-warning@-1 {{converting non-sendable function value to '@Sendable (Int, Int) -> Array<Int>' may introduce data races}}
60-
61-
// FIXME: Same here
62-
test(Array.init as (Int, Int) -> Array<Int>)
63-
// expected-warning@-1 {{converting non-sendable function value to '@Sendable (Int, Int) -> Array<Int>' may introduce data races}}
64-
}

test/Concurrency/sendable_methods.swift

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,3 +244,36 @@ do {
244244

245245
let _: () -> Void = forward(Test.fn) // Ok
246246
}
247+
248+
249+
func test_initializer_ref() {
250+
func test<T>(_: @Sendable (T, T) -> Array<T>) {
251+
}
252+
253+
let initRef: @Sendable (Int, Int) -> Array<Int> = Array<Int>.init // Ok
254+
255+
test(initRef) // Ok
256+
test(Array<Int>.init) // Ok
257+
}
258+
259+
// rdar://119593407 - incorrect errors when partially applied member is accessed with InferSendableFromCaptures
260+
do {
261+
@MainActor struct ErrorHandler {
262+
static func log(_ error: Error) {}
263+
}
264+
265+
@MainActor final class Manager {
266+
static var shared: Manager!
267+
268+
func test(_: @escaping @MainActor (Error) -> Void) {
269+
}
270+
}
271+
272+
@MainActor class Test {
273+
func schedule() {
274+
Task {
275+
Manager.shared.test(ErrorHandler.log) // Ok (access is wrapped in an autoclosure)
276+
}
277+
}
278+
}
279+
}

0 commit comments

Comments
 (0)