diff --git a/lib/Sema/CSOptimizer.cpp b/lib/Sema/CSOptimizer.cpp index df67f91bfdd3d..7cb263d55d839 100644 --- a/lib/Sema/CSOptimizer.cpp +++ b/lib/Sema/CSOptimizer.cpp @@ -17,6 +17,7 @@ #include "OpenedExistentials.h" #include "TypeChecker.h" #include "swift/AST/ConformanceLookup.h" +#include "swift/AST/Decl.h" #include "swift/AST/ExistentialLayout.h" #include "swift/AST/Expr.h" #include "swift/AST/GenericSignature.h" @@ -768,7 +769,7 @@ static std::optional preserveFavoringOfUnlabeledUnaryArgument( SmallVector favoredChoices; forEachDisjunctionChoice( cs, disjunction, - [&argumentType, &favoredChoices, &argument]( + [&cs, &argumentType, &favoredChoices, &argument]( Constraint *choice, ValueDecl *decl, FunctionType *overloadType) { if (decl->getAttrs().hasAttribute()) return; @@ -784,8 +785,15 @@ static std::optional preserveFavoringOfUnlabeledUnaryArgument( (isa(argument) || isa(argument))) return; - if (argumentType->isEqual(param.getPlainType())) + if (argumentType->isEqual(param.getPlainType())) { + if (auto *func = dyn_cast(decl)) { + if (func->isAsyncContext() != + cs.isAsynchronousContext(choice->getDeclContext())) + return; + } + favoredChoices.push_back(choice); + } }); return DisjunctionInfoBuilder(/*score=*/favoredChoices.empty() ? 0 : 1, diff --git a/test/Constraints/old_hack_related_ambiguities.swift b/test/Constraints/old_hack_related_ambiguities.swift index ff5248595cf09..d69ec110ac88b 100644 --- a/test/Constraints/old_hack_related_ambiguities.swift +++ b/test/Constraints/old_hack_related_ambiguities.swift @@ -383,3 +383,34 @@ do { } } } + +// Calls with single unlabeled arguments shouldn't favor overloads that don't match on async. +do { + struct V { + var data: Int = 0 + } + + func test(_: Int) -> Int { 42 } + func test(_: Int, v: Int = 42) async -> V? { nil } + + func doAsync(_ fn: () async -> T) async -> T { await fn() } + + func computeAsync(v: Int) async { + let v1 = await test(v) + if let v1 { + _ = v1.data // Ok + } + + let v2 = await doAsync { await test(v) } + if let v2 { + _ = v2.data // Ok + } + + _ = await doAsync { + let v = await test(v) + if let v { + _ = v.data // Ok + } + } + } +}