Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Already on GitHub? Sign in to your account

Async await prototype #11501

wants to merge 8 commits into


None yet
7 participants

lattner commented Aug 17, 2017

This implements parsing and semantic analysis support for the async/await proposal that @jckarter and I are cooking. It doesn't include SILGen support yet, so it isn't ready for merging.

lattner and others added some commits Aug 7, 2017

LuizZak commented Aug 17, 2017


@dcci dcci requested a review from DougGregor Aug 18, 2017


practicalswift commented Aug 18, 2017

Nice stuff! Welcome back! :-)


DougGregor commented Aug 24, 2017

SIL support for this feature (which is needed for it to do anything) is 10x larger and more complicated than the parsing/sema bits in this pull request, and requires significant design work. Y'all might want to hold on to those party hats.


lattner commented Aug 24, 2017

One approach does. The other approach builds on the LLVM support for coroutines (which would also allow the llvm inliner etc to work on them).

If you haven't followed the discussions in the c++ community, it is interesting to note that they landed in a very similar design space to the proposed design.


jckarter commented Aug 24, 2017

It isn't clear to me how LLVM's coroutine transform can do all the work here without any work at the SIL level. We need to at least be able to generate the destructor edge out of every await point to clean up when all references to a suspended coroutine context get released, and it seems like we'd need a new variation of apply/try_apply with a third edge to represent that. It isn't obvious to me that collecting all those destructor edges and putting them together as the heap object destructor for the coroutine context would just fall out of the llvm-level transform either.


lattner commented Aug 25, 2017

Right, I'm not saying there is zero SILGen work, I'm just saying it is a lot less if you build on the coroutine transformation and optimizations that LLVM does already.


jckarter commented Aug 25, 2017 edited

Another approach to get to a prototype stage people can play with might be to not do a coroutine transform at all, and just map begin/suspend to the awful brute-force "allocate a callstack and getcontext/setcontext to move on and off the coroutine stack". That wouldn't give you the efficiency or scalability of the real thing, but could at least get the surface semantics to a point people can experiment building things on top of.

@jckarter "allocate a callstack and getcontext/setcontext to move on and off the coroutine stack". I'm a bit curious about this topic. This would be similar to Venice coroutines which are built upon libdill coroutines, right? You mentioned before this approach is unsafe for Swift and I believe it even motivated this commit somehow, which marks functions that return twice as unavailable. I know this wouldn't be exactly the same thing because you'd be doing work inside the compiler, so whatever needs to be done to make it safe, you'd do it. I'm just curious about what would have to be done to make this approach safe.


jckarter commented Sep 21, 2017

Using setjmp/longjmp from Swift is not sound because of the returns_twice semantics of setjmp, and because longjmp unwinds the stack and Swift doesn't emit cleanup information. Suspending and resuming contexts shouldn't have that problem (assuming you're not ever trying to resume the same context twice), though there is framework code out there that will break if the stack pointer is not pointing into the kernel-allocated callstack for the current thread.

Would it be possible to initially implement async/await as simple syntax sugar for callbacks/promises?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment