@@ -1994,6 +1994,70 @@ synthesizeMainBody(AbstractFunctionDecl *fn, void *arg) {
19941994 return std::make_pair (body, /* typechecked=*/ false );
19951995}
19961996
1997+ static FuncDecl *resolveMainFunctionDecl (DeclContext *declContext,
1998+ ResolvedMemberResult &resolution,
1999+ ASTContext &ctx) {
2000+ // The normal resolution mechanism won't choose the asynchronous main function
2001+ // unless no other options are available because extensions and generic types
2002+ // (structs/classes) are not considered asynchronous contexts.
2003+ // We want them to be promoted to a viable entrypoint if the deployment target
2004+ // is high enough.
2005+ SmallVector<FuncDecl *, 4 > viableCandidates;
2006+ for (ValueDecl *candidate : resolution.getMemberDecls (Viable)) {
2007+ if (FuncDecl *function = dyn_cast<FuncDecl>(candidate)) {
2008+ if (function->isMainTypeMainMethod ())
2009+ viableCandidates.push_back (function);
2010+ }
2011+ }
2012+ if (viableCandidates.empty ()) {
2013+ return nullptr ;
2014+ }
2015+
2016+ AvailabilityContext contextAvailability =
2017+ AvailabilityContext::forDeploymentTarget (ctx);
2018+ const bool hasAsyncSupport = contextAvailability.isContainedIn (
2019+ ctx.getBackDeployedConcurrencyAvailability ());
2020+
2021+ FuncDecl *best = nullptr ;
2022+ for (FuncDecl *candidate : viableCandidates) {
2023+ // The candidate will work if it's synchronous, or if we support concurrency
2024+ // and it is async, or if we are in YOLO mode
2025+ const bool candidateWorks = !candidate->hasAsync () ||
2026+ (hasAsyncSupport && candidate->hasAsync ()) ||
2027+ ctx.LangOpts .DisableAvailabilityChecking ;
2028+
2029+ // Skip it if it won't work
2030+ if (!candidateWorks)
2031+ continue ;
2032+
2033+ // If we don't have a best, the candidate is the best so far
2034+ if (!best) {
2035+ best = candidate;
2036+ continue ;
2037+ }
2038+
2039+ // If the candidate is better and it's synchronous, just swap it right in.
2040+ // If the candidate is better and it's async, make sure we support async
2041+ // before selecting it.
2042+ //
2043+ // If it's unordered (equally bestest), use the async version if we support
2044+ // it or use the sync version if we don't.
2045+ const Comparison rank =
2046+ TypeChecker::compareDeclarations (declContext, candidate, best);
2047+ const bool isBetter = rank == Comparison::Better;
2048+ const bool isUnordered = rank == Comparison::Unordered;
2049+ const bool swapForAsync =
2050+ hasAsyncSupport && candidate->hasAsync () && !best->hasAsync ();
2051+ const bool swapForSync =
2052+ !hasAsyncSupport && !candidate->hasAsync () && best->hasAsync ();
2053+ const bool selectCandidate =
2054+ isBetter || (isUnordered && (swapForAsync || swapForSync));
2055+ if (selectCandidate)
2056+ best = candidate;
2057+ }
2058+ return best;
2059+ }
2060+
19972061FuncDecl *
19982062SynthesizeMainFunctionRequest::evaluate (Evaluator &evaluator,
19992063 Decl *D) const {
@@ -2049,37 +2113,17 @@ SynthesizeMainFunctionRequest::evaluate(Evaluator &evaluator,
20492113
20502114 auto resolution = resolveValueMember (
20512115 *declContext, nominal->getInterfaceType (), context.Id_main );
2052-
2053- FuncDecl *mainFunction = nullptr ;
2054-
2055- if (resolution.hasBestOverload ()) {
2056- auto best = resolution.getBestOverload ();
2057- if (auto function = dyn_cast<FuncDecl>(best)) {
2058- if (function->isMainTypeMainMethod ()) {
2059- mainFunction = function;
2060- }
2061- }
2062- }
2063-
2064- if (mainFunction == nullptr ) {
2065- SmallVector<FuncDecl *, 4 > viableCandidates;
2066-
2067- for (auto *candidate : resolution.getMemberDecls (Viable)) {
2068- if (auto func = dyn_cast<FuncDecl>(candidate)) {
2069- if (func->isMainTypeMainMethod ()) {
2070- viableCandidates.push_back (func);
2071- }
2072- }
2073- }
2074-
2075- if (viableCandidates.size () != 1 ) {
2076- context.Diags .diagnose (attr->getLocation (),
2077- diag::attr_MainType_without_main,
2078- nominal->getBaseName ());
2079- attr->setInvalid ();
2080- return nullptr ;
2081- }
2082- mainFunction = viableCandidates[0 ];
2116+ FuncDecl *mainFunction =
2117+ resolveMainFunctionDecl (declContext, resolution, context);
2118+ if (!mainFunction) {
2119+ const bool hasAsyncSupport =
2120+ AvailabilityContext::forDeploymentTarget (context).isContainedIn (
2121+ context.getBackDeployedConcurrencyAvailability ());
2122+ context.Diags .diagnose (attr->getLocation (),
2123+ diag::attr_MainType_without_main,
2124+ nominal->getBaseName (), hasAsyncSupport);
2125+ attr->setInvalid ();
2126+ return nullptr ;
20832127 }
20842128
20852129 auto where = ExportContext::forDeclSignature (D);
0 commit comments