-
Notifications
You must be signed in to change notification settings - Fork 214
Description
The implementation of stdexec::as_awaitable() checks that the result satisfies the __awaitable concept in the case that it dispatches to member t.as_awaitable(p) or to tag_invoke(as_awaitable, t, p).
The __awaitable concept defined here checks that __get_awaiter(x, p) returns a type that satisfies __awaiter<Promise>.
However, the __get_awaiter() method dispatches through promise.__await_transform() and then call operator co_await() on the result of that, rather than directly on the argument.
This means that when you write your own promise_type::await_transform() that wants to return stdexec::as_awaitable(something, *this) that as_awaitable() will then try to pass the result of this through await_transform() again.
It should not be doing this - checking that the result of as_awaitable() is awaitable in a given promise should just be checking that the result has an operator co_await() returns an __awaiter<Promise> or just already is an __awaiter<Promise>.
The current formulation just happens to work for cases where your await_transform() method passes its argument straight through to as_awaitable().
If the .as_awaitable() function returns an awaitable that is awaitable only in the specified Promise context, then when that type is passed through as_awaitable() again, it should fall through to either the __awaitable_sender case (which then doesn't check that the result is __awaitable, although does unnecessarily instantiates __awaitable_sender and potentially __sender_awaitable_t) or to the last case which just returns a reference to the original object.
However, if your await_transform() method performs other transforms, such as the task::promise_type which returns as_awaitable(affine_on(arg), *this), then the recursive call to await_transform() does not necessarily work.
For example, say the first time that this calls through the result of calling affine_on(arg).as_awaitable(*this) is an awaitable that is only awaitable within the specified context. Then when this result is passed through await_transform() again, this ends up passing it to affine_on() again, which will then try to treat the awaitable object as a sender and check to see if it can be adapted to a sender by awaiting it in a manufactured coroutine-type (see __connect_awaitable()).
However, the awaitable object will not be awaitable within the __connect_awaitable coroutine, because it is only awaitable in a coroutine with the original Promise type, and so the call to affine_on() will fail to compile in this case.
I think the as_awaitable() algorithm should be mandating that the result of .as_awaitable() member-function has an operator-co_await and awaiter type that is compatible with the promise type, but should not be trying to apply await_transform() again as as_awaitable() is typically used within await_transform() and thus await_transform() has likely already been applied.