Skip to content

Commit 63985a7

Browse files
committed
[Constraint system] Always add recoverable concurrency fixes.
This avoids us having to go down the less-efficient "salvage" path when dealing with concurrency issues. It also fixes overloading behavior when dealing with `@preconcurrency` and `@Sendable` functions, such as in swiftlang#59909.
1 parent 247b29d commit 63985a7

File tree

2 files changed

+57
-32
lines changed

2 files changed

+57
-32
lines changed

lib/Sema/CSSimplify.cpp

Lines changed: 38 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2719,42 +2719,47 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
27192719
}
27202720

27212721
/// The behavior limit to apply to a concurrency check.
2722-
auto getConcurrencyFixBehavior = [&](bool forSendable) {
2723-
// We can only handle the downgrade for conversions.
2724-
switch (kind) {
2725-
case ConstraintKind::Conversion:
2726-
case ConstraintKind::ArgumentConversion:
2727-
break;
2722+
auto getConcurrencyFixBehavior = [&](
2723+
bool forSendable
2724+
) -> Optional<FixBehavior> {
2725+
// We can only handle the downgrade for conversions.
2726+
switch (kind) {
2727+
case ConstraintKind::Conversion:
2728+
case ConstraintKind::ArgumentConversion:
2729+
break;
27282730

2729-
default:
2730-
return FixBehavior::Error;
2731-
}
2731+
default:
2732+
if (!shouldAttemptFixes())
2733+
return None;
2734+
2735+
return FixBehavior::Error;
2736+
}
27322737

2733-
// For a @preconcurrency callee outside of a strict concurrency context,
2734-
// ignore.
2735-
if (hasPreconcurrencyCallee(this, locator) &&
2736-
!contextRequiresStrictConcurrencyChecking(DC, GetClosureType{*this}))
2737-
return FixBehavior::Suppress;
2738+
// For a @preconcurrency callee outside of a strict concurrency
2739+
// context, ignore.
2740+
if (hasPreconcurrencyCallee(this, locator) &&
2741+
!contextRequiresStrictConcurrencyChecking(DC, GetClosureType{*this}))
2742+
return FixBehavior::Suppress;
27382743

2739-
// Otherwise, warn until Swift 6.
2740-
if (!getASTContext().LangOpts.isSwiftVersionAtLeast(6))
2741-
return FixBehavior::DowngradeToWarning;
2744+
// Otherwise, warn until Swift 6.
2745+
if (!getASTContext().LangOpts.isSwiftVersionAtLeast(6))
2746+
return FixBehavior::DowngradeToWarning;
27422747

2743-
return FixBehavior::Error;
2748+
return FixBehavior::Error;
27442749
};
27452750

27462751
// A @Sendable function can be a subtype of a non-@Sendable function.
27472752
if (func1->isSendable() != func2->isSendable()) {
27482753
// Cannot add '@Sendable'.
27492754
if (func2->isSendable() || kind < ConstraintKind::Subtype) {
2750-
if (!shouldAttemptFixes())
2751-
return getTypeMatchFailure(locator);
2752-
2753-
auto *fix = AddSendableAttribute::create(
2754-
*this, func1, func2, getConstraintLocator(locator),
2755-
getConcurrencyFixBehavior(true));
2756-
if (recordFix(fix))
2755+
if (auto fixBehavior = getConcurrencyFixBehavior(true)) {
2756+
auto *fix = AddSendableAttribute::create(
2757+
*this, func1, func2, getConstraintLocator(locator), *fixBehavior);
2758+
if (recordFix(fix))
2759+
return getTypeMatchFailure(locator);
2760+
} else {
27572761
return getTypeMatchFailure(locator);
2762+
}
27582763
}
27592764
}
27602765

@@ -2782,15 +2787,16 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
27822787
return getTypeMatchFailure(locator);
27832788
} else if (func1->getGlobalActor() && !func2->isAsync()) {
27842789
// Cannot remove a global actor from a synchronous function.
2785-
if (!shouldAttemptFixes())
2786-
return getTypeMatchFailure(locator);
2790+
if (auto fixBehavior = getConcurrencyFixBehavior(false)) {
2791+
auto *fix = MarkGlobalActorFunction::create(
2792+
*this, func1, func2, getConstraintLocator(locator),
2793+
*fixBehavior);
27872794

2788-
auto *fix = MarkGlobalActorFunction::create(
2789-
*this, func1, func2, getConstraintLocator(locator),
2790-
getConcurrencyFixBehavior(false));
2791-
2792-
if (recordFix(fix))
2795+
if (recordFix(fix))
2796+
return getTypeMatchFailure(locator);
2797+
} else {
27932798
return getTypeMatchFailure(locator);
2799+
}
27942800
} else if (kind < ConstraintKind::Subtype) {
27952801
return getTypeMatchFailure(locator);
27962802
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// RUN: %target-swift-frontend -typecheck -verify %s
2+
// REQUIRES: concurrency
3+
4+
// https://github.com/apple/swift/issues/59909
5+
struct Future<T> { }
6+
7+
extension Future {
8+
@preconcurrency
9+
func flatMap<NewValue>(_ callback: @escaping @Sendable (T) -> Future<NewValue>) -> Future<NewValue> { // #1
10+
fatalError()
11+
}
12+
}
13+
14+
extension Future {
15+
@available(*, deprecated, message: "")
16+
func flatMap<NewValue>(file: StaticString = #file, line: UInt = #line, _ callback: @escaping (T) -> Future<NewValue>) -> Future<NewValue> { // #2
17+
return self.flatMap(callback)
18+
}
19+
}

0 commit comments

Comments
 (0)