Fix #4017: Look through LdObjIfRef on the operand of await

A constrained GetAwaiter call on a type parameter that is not known to be
a value type wraps its receiver in LdObjIfRef so the reference is read
before any further arguments. ExpressionBuilder has no translation for
LdObjIfRef, so the operand was dropped. GetAwaiter takes no further
arguments, so the operand can be translated from the address, as
CallBuilder already does for call receivers.
This commit is contained in:
dualfroz committed 2026-10-16 10:07:54 +02:00
1 parent 587f5c9583
commit 3f1ef717b6
2 files changed
+18 -4

No files matched your search

@@ -16,9 +16,8 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
// Await shapes that still decompile to code that does not compile are tracked as #4017 (type
// parameter with an interface constraint), #4018 (static dynamic call) and #4019 (with
// expression); they are absent here because they have no correct output to pin yet.
// An await shape that still decompiles to code that does not compile is tracked as #4019 (with
// expression); it is absent here because it has no correct output to pin yet.
#pragma warning disable 1998
using System;
@@ -539,6 +538,16 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.AsyncAwait
await awaitable;
}
public async Task TypeParameterWithInterfaceConstraint<T>(T awaitable) where T : IAwaitable
{
await awaitable;
}
public async Task TypeParameterArrayElementWithInterfaceConstraint<T>(T[] awaitables) where T : IAwaitable
{
await awaitables[0];
}
public async Task ConfiguredTaskAwaitable(Task<int> task)
{
#if ROSLYN2
@@ -4557,7 +4557,12 @@ namespace ICSharpCode.Decompiler.CSharp
}
}
var value = Translate(inst.Value, typeHint: expectedType);
var operand = inst.Value;
if (operand is LdObjIfRef ldObjIfRef)
{
operand = ldObjIfRef.Target;
}
var value = Translate(operand, typeHint: expectedType);
if (value.Expression is DirectionExpression)
{
// we can deference the managed reference by stripping away the 'ref'