Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Oct 3, 2025

Fixes support for decompiling IL code that contains unboxing operations on value types, enabling two key scenarios that were previously failing:

Issue Description

The decompiler was missing support for unbox and unbox.any IL opcodes, causing failures when trying to decompile:

  1. Field access on boxed structs in LINQ queries:
struct Point { public int X, Y; }
IQueryable<object> qs = ...;
var query = qs.Select(o => ((Point)o).X).Decompile(); // Previously failed
  1. Generic unconstrained method calls on value types:
static int GetValueHash<T>(T value) => value.GetHashCode(); // Failed when T was a struct

Solution

Added support for both unboxing opcodes in ConvertProcessor.cs:

  • OpCodes.Unbox - Handles unboxing that returns a pointer to the value
  • OpCodes.Unbox_Any - Handles unboxing for value types or passes through reference types

Both opcodes are implemented using Expression.Convert(expression, type) to generate proper expression trees that represent the unboxing operation. The implementation was placed in ConvertProcessor since unboxing is fundamentally a type conversion operation, alongside other conversion operations like castclass and numeric conversions.

Examples

After this fix, the following scenarios now work correctly:

// Boxed struct field access
Expression<Func<object, int>> result = o => ((Point)o).X;
// Decompiles to: Convert(o, Point).X

// Generic value type method calls  
Expression<Func<int, int>> result = value => value.GetHashCode();
// Decompiles correctly for value types

// Nullable unboxing
Expression<Func<object, int?>> result = o => (int?)o;
// Decompiles to: Convert(o, Nullable`1)

Testing

Added comprehensive test coverage with 7 test cases covering all unboxing scenarios including edge cases with enums, nullable types, and computed properties. All tests pass successfully.

The implementation follows existing patterns in the codebase and maintains full backward compatibility.

Original prompt

This section details on the original issue you should resolve

<issue_title>Support Unbox* opcodes for value-type decompilation</issue_title>
<issue_description>#### 1. Field access on boxed struct
C#:

struct Point
{
    public int X;
    public int Y;
    [Computed] public int Sum => X + Y;
}

IQueryable<object> qs = ...;

var query = qs
    .Select(o => ((Point)o).X)
    .Decompile(); // needs unbox.any support

2. Generic unconstrained usage

static int GetValueHash<T>(T value) => value.GetHashCode(); // may produce unbox.any when T is a struct
```</issue_description>

## Comments on the Issue (you are @copilot in this section)

<comments>
</comments>
Fixes #276

💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI changed the title [WIP] Support Unbox* opcodes for value-type decompilation Add support for Unbox and Unbox_Any opcodes for value-type decompilation Oct 3, 2025
Copilot AI requested a review from hazzik October 3, 2025 05:23
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.

Support Unbox* opcodes for value-type decompilation

2 participants