Skip to content

Commit 77e9025

Browse files
committed
Sema: Don't score a solution higher if there's a sync-vs-async mismatch with a 'reasync' function
This fixes a performance regression with the reasync '&&', '||' and '??' operators. Also arguably it makes sense anyway since 'reasync' functions can in fact be called from synchronous functions, so the solution should not be considered worse. We don't actually want to be able to overload a synchronous function with a 'reasync' function anyway; the whole point of 'reasync' is to avoid the need for such overloading. Fixes rdar://problem/76254445.
1 parent 37097c1 commit 77e9025

File tree

2 files changed

+32
-1
lines changed

2 files changed

+32
-1
lines changed

lib/Sema/ConstraintSystem.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2890,7 +2890,8 @@ void ConstraintSystem::resolveOverload(ConstraintLocator *locator,
28902890
// If we're choosing an asynchronous declaration within a synchronous
28912891
// context, or vice-versa, increase the async/async mismatch score.
28922892
if (auto func = dyn_cast<AbstractFunctionDecl>(decl)) {
2893-
if (func->isAsyncContext() != isAsynchronousContext(useDC)) {
2893+
if (!func->hasPolymorphicEffect(EffectKind::Async) &&
2894+
func->isAsyncContext() != isAsynchronousContext(useDC)) {
28942895
increaseScore(
28952896
func->isAsyncContext() ? SK_AsyncInSyncMismatch : SK_SyncInAsync);
28962897
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// RUN: %target-typecheck-verify-swift -enable-experimental-concurrency
2+
3+
// We don't want 'reasync' overloads to have a higher score in the
4+
// case of a sync vs reasync mismatch the way 'async' overloads do,
5+
// since this would change solver performance characteristics when
6+
// using the reasync '&&', '||' and '??' operators.
7+
8+
func asyncOverload(_: () async -> (), _: Int) async {}
9+
func asyncOverload(_: () -> (), _: String) {}
10+
11+
func referencesAsyncOverload() {
12+
_ = asyncOverload // we prefer the sync overload
13+
}
14+
15+
func referencesAsyncOverloadAsync() async {
16+
_ = asyncOverload // we prefer the async overload
17+
}
18+
19+
func reasyncOverload(_: () async -> (), _: Int) reasync {} // expected-note {{found this candidate}}
20+
func reasyncOverload(_: () -> (), _: String) {} // expected-note {{found this candidate}}
21+
22+
func referencesReasyncOverload() {
23+
_ = reasyncOverload // expected-error {{ambiguous use of 'reasyncOverload'}}
24+
}
25+
26+
func referencesReasyncOverloadAsync() async {
27+
// we prefer the async overload because the sync overload scores higher
28+
// due to a sync-vs-async mismatch.
29+
_ = reasyncOverload
30+
}

0 commit comments

Comments
 (0)