Roslyn: `await` should be a keyword in a non-async local function inside an async method

Created on 13 Mar 2018  路  7Comments  路  Source: dotnet/roslyn

From the spec:

Inside of an async function, await cannot be used as an identifier

A non-async local function that is inside an async method is still "inside" of an async function, and therefore await should be a keyword.

But the parser currently treats await as an ordinary identifier there.

The parser appears to handle lambdas properly.

Area-Compilers Bug

Most helpful comment

The question is how to interpret this:

Inside of an async function, await cannot be used as an identifier

If i have:

c# async void M() { Func<Task> f = () => { /*here*/ }; }

in 'here' am i inside an async function? I don't personally think so. I think i'm "inside a non-async function". it seems 'strange' to me that the modifiers of a much outer function reach 'into' a deeper function. I agree 'inside' is vague and can be interpreted either way. But it doesn't seem sensible to me to take teh current parser interpretation. instead, each function scope is 'fresh', with its own modifiers defining how it should parse.

Note: this is also how TS/JS view the world. I can check other languages later tonight.

All 7 comments

Just a note about VB: there the spec says

Await is a reserved word if the immediately enclosing method or lambda expression in which it appears has an Async modifier

and the implementation matches that.
Was it intentional to have a different handling of this between C# & VB?

The question is how to interpret this:

Inside of an async function, await cannot be used as an identifier

If i have:

c# async void M() { Func<Task> f = () => { /*here*/ }; }

in 'here' am i inside an async function? I don't personally think so. I think i'm "inside a non-async function". it seems 'strange' to me that the modifiers of a much outer function reach 'into' a deeper function. I agree 'inside' is vague and can be interpreted either way. But it doesn't seem sensible to me to take teh current parser interpretation. instead, each function scope is 'fresh', with its own modifiers defining how it should parse.

Note: this is also how TS/JS view the world. I can check other languages later tonight.

My point is this: i don't want to argue the meaning of the current phrasing. I think it's pretty vague and confusing (what does 'inside' mean) and can be rightfully interpreted in multiple ways.. Instead, i would just things to be explicit in the spec, i.e.:

  1. if the immediately containing function-like thing has the 'async' modifier, 'await' cannot be used as an identifier. Or:
  2. if *any lexically containing function-like thing has the 'async' modifier, 'await' cannot be used as an identifier.

i.e. the spec should be clearer what it uses words like 'contained' and 'inside'.

--

Note: i would go with '1'. It seems far more expected and consistent. I'm also ok with '2'. But we should still make the text clear.

Finally, if we go with '1' or '2', i think it goes without saying that we should apply this consistently to all function-like things that can have an async-modifier. Methods/Lambdas/Anon-Methods/Local-Functions should all behave uniformly here :)

@CyrusNajmabadi I have no problem with the spec being clarified. The spec already uses the phrase "immediately enclosing" when it means that (unlike here).

Thanks. Sounds good to me!

Thanks. Sounds good to me!

Was this page helpful?
0 / 5 - 0 ratings