Fix #4019: Recognize with expressions whose initializer awaits

Roslyn spills the receiver of an initializer assignment that precedes an
await into a hoisted temporary, so the clone of a with expression (and the
object of an object initializer) reaches the initializer transform through
a copy it rejects. Only copies between two hoisted compiler temporaries are
inlined: folding copies of hoisted user locals as well would turn a user's
local into an initializer.
This commit is contained in:
dualfroz committed 2026-10-10 17:52:06 +02:00
1 parent ef47a24511
commit 85285c1cea
4 files changed
+50 -4

No files matched your search

@@ -668,12 +668,17 @@ namespace ICSharpCode.Decompiler.IL.Transforms
case OpCode.SwitchInstruction:
return true;
case OpCode.LdLoc:
if (v.StateMachineField == null && ((LdLoc)inlinedExpression).Variable.StateMachineField != null)
var copiedVariable = ((LdLoc)inlinedExpression).Variable;
if (v.StateMachineField == null && copiedVariable.StateMachineField != null)
{
// Roslyn likes to put the result of fetching a state machine field into a temporary variable,
// so inline more aggressively in such cases.
return true;
}
if (IsHoistedCompilerTemporary(v) && IsHoistedCompilerTemporary(copiedVariable))
{
return true;
}
break;
}
if (inlinedExpression.ResultType == StackType.Ref)
@@ -773,6 +778,13 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}
}
static bool IsHoistedCompilerTemporary(ILVariable v)
{
string name = v.StateMachineField?.Name;
return name != null
&& (name.StartsWith("<>7__wrap", StringComparison.Ordinal) || name.StartsWith("<>s__", StringComparison.Ordinal));
}
/// <summary>
/// Gets whether 'expressionBeingMoved' can be inlined into 'expr'.
/// </summary>