When a dynamic argument list containing an await is passed to a static method, the call site's typeof(TargetType) marker is materialized as a receiver variable, and the static call is rewritten as an instance call on that Type.
Input
public async Task DynamicAwaitInStaticCall(dynamic value)
{
Console.WriteLine("x" + await value);
}
Actual output
public async Task DynamicAwaitInStaticCall(dynamic value)
{
Type typeFromHandle = typeof(Console);
typeFromHandle.WriteLine("x" + await value);
}
This is CS1061 (Type has no WriteLine).
Expected output
public async Task DynamicAwaitInStaticCall(dynamic value)
{
Console.WriteLine("x" + await value);
}
Notes
The await is what triggers it. Both of these round-trip correctly:
- the same call without the
await (Console.WriteLine("x" + value))
- the same
await in a dynamic instance call
For a static dynamic call, Roslyn passes typeof(Console) to the call site as the target-type marker. Without a suspension point that ldtoken/GetTypeFromHandle pair stays inline and is recognized; the state-machine split hoists it into its own local first, and the dynamic-call transform then treats the local as an ordinary receiver.
When a
dynamicargument list containing anawaitis passed to a static method, the call site'stypeof(TargetType)marker is materialized as a receiver variable, and the static call is rewritten as an instance call on thatType.Input
Actual output
This is CS1061 (
Typehas noWriteLine).Expected output
Notes
The
awaitis what triggers it. Both of these round-trip correctly:await(Console.WriteLine("x" + value))awaitin a dynamic instance callFor a static dynamic call, Roslyn passes
typeof(Console)to the call site as the target-type marker. Without a suspension point thatldtoken/GetTypeFromHandlepair stays inline and is recognized; the state-machine split hoists it into its own local first, and the dynamic-call transform then treats the local as an ordinary receiver.