Skip to content

Conversation

Copilot
Copy link
Contributor

@Copilot Copilot AI commented Jul 31, 2025

Assignment expressions were incorrectly decompiled as Block expressions containing both the assignment and the assigned value, instead of returning a single assignment expression.

Problem

When decompiling assignment expressions like:

Func<MyClass, string> func = v => v.MyProperty = "I wish to assign this value";
LambdaExpression decompiled = DecompileExtensions.Decompile(func);

The decompiled body was a Block expression containing:

  1. Binary expression (node type Assign): (v.MyProperty = "I wish to assign this value")
  2. Constant expression: "I wish to assign this value"

But it should be just the single assignment expression.

Root Cause

The C# compiler generates IL that duplicates the assigned value on the stack:

  • ldstr - Load the string constant
  • dup - Duplicate it (two copies on stack)
  • stloc.0 - Store one copy to local variable
  • callvirt set_Property - Call setter with other copy
  • ldloc.0 - Load stored copy as return value

The decompiler was processing both the assignment operation and the return value separately, creating a Block with both expressions.

Solution

Added optimization logic to OptimizeExpressionVisitor.VisitBlock() to detect when a block contains an assignment expression followed by the same value that was assigned. In this case, it returns only the assignment expression since assignment expressions already return the assigned value in expression trees.

The fix uses direct expression equality (==) for reliable comparison, consistent with patterns used elsewhere in the codebase. This works because the C# compiler's 'dup' instruction results in the same expression object being referenced in both positions.

The optimization properly belongs in the OptimizeExpressionVisitor rather than during decompilation, separating concerns between IL processing and expression tree optimization.

The fix handles both simple constants and complex expressions:

  • v => v.MyProperty = "test"
  • v => v.StartDate = new DateTime(2023, 1, 1)

Tests Added

  • ShouldDecompilePropertyAssignmentExpression - Tests string constant assignment
  • ShouldDecompileComplexAssignmentExpression - Tests complex expression assignment

Fixes #260.


💬 Share your feedback on Copilot coding agent for the chance to win a $200 gift card! Click here to start the survey.

@Copilot Copilot AI changed the title [WIP] Assignment expression not converted properly Fix assignment expression decompilation to return single assignment instead of block Jul 31, 2025
@Copilot Copilot AI requested a review from hazzik July 31, 2025 02:52
Copilot finished work on behalf of hazzik July 31, 2025 02:52
@Copilot Copilot AI requested a review from hazzik July 31, 2025 03:05
Copilot finished work on behalf of hazzik July 31, 2025 03:05
@Copilot Copilot AI requested a review from hazzik July 31, 2025 03:18
Copilot finished work on behalf of hazzik July 31, 2025 03:18
Copilot finished work on behalf of hazzik July 31, 2025 03:20
Copy link
Owner

@hazzik hazzik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you integrate tests into existing test patterns? I think there is assignment tests or something existing.

Copy link
Contributor Author

Copilot AI commented Aug 4, 2025

Can you integrate tests into existing test patterns? I think there is assignment tests or something existing.

Integrated the assignment expression tests into the existing AssignmentTests.cs file using the standard Test() pattern from DecompilerTestsBase. The tests now follow the established patterns in the codebase and the separate AssignmentExpressionTests.cs file has been removed. (commit 8f6f182)

@Copilot Copilot AI requested a review from hazzik August 4, 2025 02:09
Copilot finished work on behalf of hazzik August 4, 2025 02:09
@hazzik
Copy link
Owner

hazzik commented Aug 4, 2025

Thanks, but it does not compile anymore

Copy link
Contributor Author

Copilot AI commented Aug 4, 2025

Thanks, but it does not compile anymore

Fixed the compilation errors in commit bc09c03. The issue was that C# doesn't allow assignment operators directly in expression trees (CS0832 error). Changed the tests to use Expression.Assign() to manually construct the expected assignment expressions instead of lambda syntax with assignments. Tests are now compiling and passing.

Copilot finished work on behalf of hazzik August 4, 2025 02:38
@Copilot Copilot AI requested a review from hazzik August 4, 2025 03:28
Copilot finished work on behalf of hazzik August 4, 2025 03:28
@Copilot Copilot AI requested a review from hazzik August 4, 2025 03:36
Copilot finished work on behalf of hazzik August 4, 2025 03:36
Copilot finished work on behalf of hazzik August 4, 2025 03:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Assignment expression not converted properly

2 participants