Skip to content

Commit c01b9f0

Browse files
committed
Adding async-main support
This patch adds the async-main start-point for programs. When a `static func main() async` is inserted into the main program, it gets called through `_runAsyncMain` instead of calling directly. This starts the program in an async context, which is good because then we can do async stuff from there. The following code ``` @main struct MyProgram { static func main() async { // async code } } ``` is turned into ``` @main struct MyProgram { static func $main() { _runAsyncMain(main) } static func main() async { // async code } } ``` _runAsyncMain code-gen's to the same thing as runAsyncAndBlock, which emits a call to `swift_task_runAndBlockThread`.
1 parent 02b42e2 commit c01b9f0

File tree

3 files changed

+58
-1
lines changed

3 files changed

+58
-1
lines changed

lib/Sema/TypeCheckAttr.cpp

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1935,7 +1935,31 @@ synthesizeMainBody(AbstractFunctionDecl *fn, void *arg) {
19351935

19361936
Expr *returnedExpr;
19371937

1938-
if (mainFunction->hasThrows()) {
1938+
if (mainFunction->hasAsync()) {
1939+
// Pass main into _runAsyncMain(_ asyncFunc: () async -> ())
1940+
// Resulting $main looks like:
1941+
// $main() { _runAsyncMain(main) }
1942+
auto *concurrencyModule = context.getLoadedModule(context.Id_Concurrency);
1943+
assert(concurrencyModule != nullptr && "Failed to find Concurrency module");
1944+
1945+
SmallVector<ValueDecl *, 1> decls;
1946+
concurrencyModule->lookupQualified(
1947+
concurrencyModule,
1948+
DeclNameRef(context.getIdentifier("_runAsyncMain")),
1949+
NL_QualifiedDefault | NL_IncludeUsableFromInline,
1950+
decls);
1951+
assert(!decls.empty() && "Failed to find _runAsyncMain");
1952+
FuncDecl *runner = cast<FuncDecl>(decls[0]);
1953+
1954+
auto asyncRunnerDeclRef = ConcreteDeclRef(runner, substitutionMap);
1955+
1956+
DeclRefExpr *funcExpr = new (context) DeclRefExpr(asyncRunnerDeclRef,
1957+
DeclNameLoc(),
1958+
/*implicit=*/true);
1959+
funcExpr->setType(runner->getInterfaceType());
1960+
auto *callExpr = CallExpr::createImplicit(context, funcExpr, memberRefExpr, {});
1961+
returnedExpr = callExpr;
1962+
} else if (mainFunction->hasThrows()) {
19391963
auto *tryExpr = new (context) TryExpr(
19401964
callExpr->getLoc(), callExpr, context.TheEmptyTupleType, /*implicit=*/true);
19411965
returnedExpr = tryExpr;

stdlib/public/Concurrency/Task.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,9 @@ func isTaskCancelled(_ task: Builtin.NativeObject) -> Bool
323323
@_silgen_name("swift_task_runAndBlockThread")
324324
public func runAsyncAndBlock(_ asyncFun: @escaping () async -> ())
325325

326+
@_silgen_name("swift_task_runAndBlockThread")
327+
public func _runAsyncMain(_ asyncFun: () async throws -> ())
328+
326329
@_silgen_name("swift_task_future_wait")
327330
func _taskFutureWait(
328331
on task: Builtin.NativeObject

test/Concurrency/async_main.swift

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// RUN: %target-swift-frontend -dump-ast -enable-experimental-concurrency -parse-as-library %s | %FileCheck %s --check-prefix=CHECK-AST
2+
// REQUIRES: concurrency
3+
4+
func asyncFunc() async { }
5+
6+
@main struct MyProgram {
7+
static func main() async {
8+
await asyncFunc()
9+
}
10+
}
11+
12+
13+
// CHECK-AST-LABEL: "main()" interface
14+
// CHECK-AST: (await_expr type='()'
15+
// CHECK-AST-NEXT: (call_expr type='()'
16+
// CHECK-AST-NEXT: (declref_expr type='() async -> ()'
17+
// CHECK-AST-SAME: decl=async_main.(file).asyncFunc()@
18+
19+
// CHECK-AST-LABEL: (func_decl implicit "$main()" interface
20+
// CHECK-AST: (brace_stmt
21+
// CHECK-AST-NEXT: (return_stmt implicit
22+
// CHECK-AST-NEXT: (call_expr implicit type='()'
23+
// CHECK-AST-NEXT: (declref_expr implicit
24+
// CHECK-AST-SAME: type='(() async throws -> ()) -> ()'
25+
// CHECK-AST-SAME: decl=_Concurrency.(file)._runAsyncMain
26+
// CHECK-AST-SAME: function_ref=single
27+
// CHECK-AST-NEXT: (paren_expr implicit type='(() async throws -> ())'
28+
// CHECK-AST-NEXT: (function_conversion_expr implicit type='() async throws -> ()'
29+
// CHECK-AST-NEXT: (dot_syntax_call_expr
30+
// CHECK-AST-NEXT: (autoclosure_expr implicit type='(MyProgram.Type) -> () async -> ()'

0 commit comments

Comments
 (0)