Awaiting a type parameter constrained to an awaitable interface produces output that does not compile: the operand is dropped and replaced with an unsupported-opcode comment.
Input
public interface IAwaitable
{
TaskAwaiter GetAwaiter();
}
public async Task TypeParameterWithInterfaceConstraint<T>(T value) where T : IAwaitable
{
await value;
}
Actual output
public async Task TypeParameterWithInterfaceConstraint<T>(T value) where T : IAwaitable
{
await (IAwaitable)/*OpCode not supported: LdObjIfRef*/;
}
This is CS0119.
Expected output
public async Task TypeParameterWithInterfaceConstraint<T>(T value) where T : IAwaitable
{
await value;
}
Notes
The constrained. prefixed callvirt to GetAwaiter lowers to an LdObjIfRef, and ExpressionBuilder has no case for that instruction, so the operand is lost entirely.
The sibling shapes decompile correctly, which narrows this to the interface-constrained case:
where T : ClassAwaitable (class constraint) round-trips
where T : struct, IAwaitable round-trips
Both are covered by AwaitReceivers.TypeParameterWithClassConstraint / TypeParameterWithStructConstraint in ICSharpCode.Decompiler.Tests/TestCases/Pretty/AsyncAwaitPatterns.cs.
Awaiting a type parameter constrained to an awaitable interface produces output that does not compile: the operand is dropped and replaced with an unsupported-opcode comment.
Input
Actual output
This is CS0119.
Expected output
Notes
The
constrained.prefixedcallvirttoGetAwaiterlowers to anLdObjIfRef, andExpressionBuilderhas no case for that instruction, so the operand is lost entirely.The sibling shapes decompile correctly, which narrows this to the interface-constrained case:
where T : ClassAwaitable(class constraint) round-tripswhere T : struct, IAwaitableround-tripsBoth are covered by
AwaitReceivers.TypeParameterWithClassConstraint/TypeParameterWithStructConstraintinICSharpCode.Decompiler.Tests/TestCases/Pretty/AsyncAwaitPatterns.cs.