- Notifications
You must be signed in to change notification settings - Fork8.1k
Add support for ITuple and Deconstruct assignment to multiple variables#26617
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
base:master
Are you sure you want to change the base?
Add support for ITuple and Deconstruct assignment to multiple variables#26617
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Pull request overview
This pull request adds tuple deconstruction support to PowerShell, enablingITuple types (Tuple, ValueTuple) and types withDeconstruct methods (DictionaryEntry, KeyValuePair<,>) to be assigned to multiple variables using array assignment syntax. This addresses issue#7471 by implementing special handling in the dynamic binding layer to automatically decompose these types into their constituent elements during assignment operations.
Key changes:
- Enhanced
PSGetMemberBinderto detect and handle ITuple interface and Deconstruct methods - Added helper methods in
EnumerableOpsfor slicing tuples and invoking deconstruction - Comprehensive test coverage with 13 new tests for various tuple and deconstruction scenarios
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| test/powershell/Language/Scripting/Indexer.Tests.ps1 | Added 13 comprehensive tests covering ITuple and Deconstruct assignment scenarios including edge cases (underflow, overflow, single Deconstruct call verification) |
| src/System.Management.Automation/engine/runtime/Operations/MiscOps.cs | Implemented four helper methods in EnumerableOps: GetTupleSlice, GetDeconstructMethod, InvokeDeconstruct, and GetDeconstructSlice for tuple and deconstruct operations |
| src/System.Management.Automation/engine/runtime/Binding/Binders.cs | Extended PSGetMemberBinder.FallbackGetMember with ITuple and Deconstruct detection and handling logic with proper dynamic restrictions |
| src/System.Management.Automation/engine/parser/Compiler.cs | Added cached reflection info for ITuple properties/methods and EnumerableOps helper methods to improve runtime performance |
💡Add Copilot custom instructions for smarter, more guided reviews.Learn how to get started.
src/System.Management.Automation/engine/runtime/Operations/MiscOps.cs OutdatedShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
…cOps.csCo-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
| variTuple=target.ValueasSystem.Runtime.CompilerServices.ITuple; | ||
| if(iTupleis notnull) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
| variTuple=target.ValueasSystem.Runtime.CompilerServices.ITuple; | |
| if(iTupleisnotnull) | |
| variTuple=target.ValueasSystem.Runtime.CompilerServices.ITuple; | |
| if(target.ValueisITupleiTuple) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Thank you for the quick feedback! Applied with correction (merged both lines into one). Commit:1d4f6a6
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
System.Runtime.CompilerServices is still used in 5 points. Please remove.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Sorry for missing those. Removed the prefix from 4 occurrences in my changes:
- Compiler.cs (lines 301, 304)
- Binders.cs (line 1082)
- MiscOps.cs (line 3651)
The 5th reference in CorePsTypeCatalog.cs is not my code. It's an auto-generated type catalog string literal. Should I update that one as well?
Commit:89b0793
src/System.Management.Automation/engine/runtime/Binding/Binders.cs OutdatedShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
| } | ||
| It'Hashtable enumeration produces deconstructable DictionaryEntry' { | ||
| $ht=@{name="test" } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Does the feature work for PSCustomObject?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
No,PSCustomObject is not supported. It doesn't implementITuple,IList, or have aDeconstruct method.
I intentionally didn't add support becausePSCustomObject properties are name-based, not position-based. Order-based deconstruction would be fragile:
$person= [PSCustomObject]@{name="John";age=30 }$name,$age=$person# Works# Later, add a property...$person= [PSCustomObject]@{id=1;name="John";age=30 }$name,$age=$person# Silently breaks: $name = 1, $age = "John"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Name-based matching (like JavaScript'sconst { name, age } = person) would be safer, but I believe that would require a different approach and new syntax—beyond the scope of this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Yes, it seems we have such issue for named arguments and could enhance it to the area.
…s.csCo-authored-by: Ilya <darpa@yandex.ru>
iSazonov left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
@yotsuda Although this is a great feature, I can't imagine when the owners of the code will find the time to do a review. Let's be patient.
PR Summary
Adds support for assigning
ITupletypes (System.Tuple,System.ValueTuple) and types withDeconstructmethods (DictionaryEntry,KeyValuePair<,>, etc.) to multiple variables using array assignment syntax.Fixes#7471
PR Context
Problem
When assigning a
Tuple,ValueTuple,DictionaryEntry, orKeyValuePairto multiple variables, PowerShell previously assigned the entire object to the first variable instead of deconstructing it:This prevented convenient use of APIs that return tuples (like
[Math]::DivRem()) and made hashtable enumeration cumbersome.Solution
Added special handling in
PSGetMemberBinderfor two cases:System.Runtime.CompilerServices.ITupleinterface, elements extracted using the indexerDeconstructmethod with alloutparameters (likeDictionaryEntryandKeyValuePair<,>)Both handle three scenarios: exact match, fewer elements than variables (fills with null), more elements than variables (remaining go to last variable as array).
PR Checklist
.h,.cpp,.cs,.ps1and.psm1files have the correct copyright headerChanges Made
1.
Compiler.cs(+18 lines)ITuple.Lengthproperty andITuple.get_ItemmethodEnumerableOps.GetTupleSlice,GetDeconstructMethod,InvokeDeconstruct, andGetDeconstructSlicemethods2.
Binders.cs(+120 lines)ITupledetection and handling inPSGetMemberBinder.FallbackGetMemberDeconstructmethod detection and handling3.
MiscOps.cs(+97 lines)GetTupleSlice- extracts remaining elements from ITupleGetDeconstructMethod- finds Deconstruct method on a typeInvokeDeconstruct- invokes Deconstruct and returns valuesGetDeconstructSlice- extracts remaining values from already-deconstructed array (avoids calling Deconstruct multiple times)4.
Indexer.Tests.ps1(+136 lines)Total: 4 files changed, 371 insertions(+)
Behavior Examples
Tuple assignment
(1, 2)tuple object$null12DictionaryEntry assignment
DictionaryEntryobject$null"key""value"KeyValuePair assignment
KeyValuePairobject$null"count"42Hashtable enumeration
DictionaryEntryobject$null"name""test"Math.DivRem
(3, 2)ValueTuple object$null32Testing
Test Cases (13 new tests)
ITuple tests:
Deconstruct tests:
9. DictionaryEntry assignment
10. KeyValuePair assignment
11. DictionaryEntry with more variables than elements
12. Hashtable enumeration practical example
13. Deconstruct method called only once (verifies no redundant calls)
Test Results
Implementation Details
Supported Types
Via ITuple interface:
System.Tuple<>(1-8 elements)System.ValueTuple<>(1-8 elements)System.Runtime.CompilerServices.ITupleVia Deconstruct method:
System.Collections.DictionaryEntrySystem.Collections.Generic.KeyValuePair<,>Deconstruct(out T1, out T2, ...)methodDesign Decisions