Skip to content

C#: Data flow for implicit deconstruct calls. - #22861

Draft
michaelnebel wants to merge 5 commits into
github:mainfrom
michaelnebel:csharp/deconstruct
Draft

michaelnebel wants to merge 5 commits into
github:mainfrom
michaelnebel:csharp/deconstruct

Conversation

@michaelnebel

@michaelnebel michaelnebel commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

In this PR we introduce data flow support for implicit deconstruct calls.

The example below is valid C# syntax and the assignment var (x, y) = r implicitly invokes the compiler generated Deconstruct method on r.

public record R(string S, object O)
...
var r = new R("S", new object())
var (x, y) = r

The last assignment is equivalent to

r.Deconstruct(out var x0, out var y0)
var (x, y) = (x0, y0).

The QL implementation contains the following

  • Predicate for identifying expressions where deconstruct is implicitly called.
  • Synthetic data flow nodes for the deconstruct call, the deconstruct out parameters (and the receiver argument node for the synthetic call).
  • Flow summaries for compiler generated deconstruct methods.
  • Only deconstruct calls in assignments and pattern matching are covered in this PR.

Furthermore, there is also the following limitations

  • Only one level of deconstruct supported.
  • Deconstruct extension methods are not supported.
  • Foreach loop variable assignment is not covered.

Note, that value tuples don't have a deconstruct method and the tuple classes have deconstruct extension methods. If we want replace the existing tuple logic, we need to support deconstruct extension methods and support nested deconstructs.

@github-actions github-actions Bot added the C# label Oct 21, 2026
@michaelnebel
michaelnebel force-pushed the csharp/deconstruct branch 2 times, most recently from 46fe603 to adf869e Compare October 22, 2026 10:00
Comment thread csharp/ql/lib/semmle/code/csharp/frameworks/System.qll Fixed
@michaelnebel
michaelnebel force-pushed the csharp/deconstruct branch 4 times, most recently from e275353 to 393c574 Compare October 22, 2026 13:15
Comment on lines +1919 to +1925
/**
* Holds, if there is an implicit call to the to the `deconstruct` method at `source`, where `target` is the expression
* receiving the deconstructed values, and `tt` is the tuple type of the `target` expression.
* The method may be declared on the source type or inherited from a base class.
*
* Example: `var (x, y) = r;` where `r` is of type `R` with a `Deconstruct` method.
*/

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants