It is a known issue, and we do not anticipate making a change here at this time. #expect() is a macro and macros in Swift can see syntax, but can't see type or effects information. In order to correctly expand an await or try expression, we need to know exactly which subexpressions require those keywords so that we can reapply them in the right places in the macro's expanded form.
(For those who come across this in the future, the linked GitHub issue made me realise that in my case I can actually just move the await outside the #expect and this solves it.)
That will break in other ways depending on the expression you're writing, because macros cannot see syntax nodes (e.g. keywords) outside of themselves, so we don't know anything's going to be awaitable. Tread with caution.
Do you think you could give an example of a usage that might "break in other ways", please? It might help me understand whether I should switch back to the previous way I was doing things
If I write something like await #expect(true), then I get a (helpful) compiler warning of "No 'async' operations occur within 'await' expression", which I would expect. Is that what you're referring to or am I way off the mark?
This function fails to compile with a warning and an error:
No 'async' operations occur within 'await' expression
'async' call in a function that does not support concurrency
By default, the #expect() macro tries to break down condition expressions in order to get the complex failure messages that we all love so dearly. Because Swift Testing cannot tell that g() needs an await keyword when called, it doesn't emit one in the expansion of await #expect(f()), so it ends up calling f() without an await keyword (generating the error) while the expanded form of the macro is not itself async (generating the warning.)
trying to use await or try before #expect may or may not cause a compiler error, and it's hard for an average user to predict whether it will for a given use case
but if in a particular use case it doesn’t cause a compiler error, then there is no harm in doing so (and will give better failure messages)
The behaviour is undefined; in the future, we expect to change it to always behave as if the keyword were inside the parentheses (and skip expanding the expression) so at best you're looking at a temporary quirk of the library here, not a permanent feature.
If you want to get the full expansion reliably, consider moving await outside of #expect():
let currentStatus = await status.current
#expect(currentStatus == .attached)