I thought about async-unwinding more and I think this is the starting point:
I think the ideal API would be a catch_unwind_async, which takes a future and returns a future combinator that also includes the states to unwind the future if it panics. Then instead of wrapping their polls in catch_unwind, executors would wrap the futures they spawn in catch_unwind_async and poll those to completion. When entering the poll method of this combinator, a thread local flag is set to trigger the async unwinding path when panics happen. (If catch_unwind is called inside of this scope, the flag is set back to normal).
The question is whether or not it's possible to create the future combinator which unwinds a future. I really have no knowledge in that domain.
My take on this is that the Future doesn't necessary has to contain the cancel method. A graceful cancellation request could be provided to any code via an orthogonal mechanism. I proposed a standardized CancellationToken mechanism for this:
If that token/signal is injected via some standardized mechanims (thread-local or task-local variable), anything in the future could react on it and gracefully run the future to the completed state. The Future could continue to just have a single .poll method, and another bonus is that the standardized cancellation signal can be shared between synchronous and asynchronous contexts.
Overall I think there's at least 3 orthogonal aspects, which however are all closely related:
Async drop (or just something like an IAsyncDisposable as @scottmcm pointed out), plus potential extra tools to make it more likely to be called (let async declarations, async defer blocks, etc).
Run to completion async fns - which would at least guarantee that code containing an let async binding would indeed run the destructure, instead of being short-circuited by any select! or synchronous drop in the call-stack.
I think that distinguishing syntactically between a completion future and a readiness future is an unnecessary burden that will probably cause a lot of trouble. I think having it be inferred like Send and Sync is probably the best choice.
Also poll_cancel would be basically optional, because it has a sound default implementation. Using a method is probably better than using a global for cancellation.