-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Deconstruction-assignment: nested scenario #11715
Conversation
Error(diagnostics, ErrorCode.ERR_DeconstructRequiresExpression, node); | ||
return BadExpression(node, checkedVariables.Concat(boundRHS).ToArray()); | ||
} | ||
} |
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.
Can this if
be moved before try/finally
and deconstructionSteps
declaration?
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, indeed. Thanks
<Field Name="AssignmentSteps" Type="ImmutableArray<BoundDeconstructionAssignmentOperator.AssignmentStep>" Null="NotApplicable" SkipInVisitor="true"/> | ||
</Node> | ||
|
||
<Node Name="BoundDeconstructionVariables" Base="BoundExpression"> |
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.
Why a BoundExpression
rather than BoundNode
?
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.
So, this bound node is never output from binding at all. But during binding, I have bound expressions for the LHS, which need to be organized in a tree.
Because all simple variables are BoundExpression
, it is convenient that this is also BoundExpression
(rather than BoundNode
). But I'm open to suggestions.
I agree that having a bound node that never escapes binding is strange.
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.
Where do we use checkedVariables
as (array of) BoundExpression
rather than BoundNode
? Or is it more than just checkedVariables
that is the concern?
DiagnosticBag bag = new DiagnosticBag(); | ||
MethodSymbol deconstructMethod = FindDeconstruct(checkedVariables, boundRHS, node, bag); | ||
var bag = DiagnosticBag.GetInstance(); | ||
MethodSymbol deconstructMethod = FindDeconstruct(variables.Length, targetPlaceholder, syntax, bag); | ||
if (!diagnostics.HasAnyErrors()) |
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.
Is bag
only added if diagnostics
is empty to avoid cascading errors? Are we sure existing diagnostics are from the same expression (in other words, are we sure bag
contains errors related to those in diagnostics
)? Perhaps add bag
always.
/// </summary> | ||
static private DeconstructStep MakeNonTupleDeconstructStep( | ||
BoundDeconstructValuePlaceholder targetPlaceholder, | ||
AssignmentExpressionSyntax syntax, |
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.
Same comment about associated syntax node.
Done with the review pass |
Pushed some commits addressing the feedback. |
Having BoundDeconstructionVariables as a helper node seems fine as long as it doesn't survive initial binding. It does provide an easy way to track relevant syntax node. Otherwise we would have to use a tuple for this. In reply to: 223733070 [](ancestors = 223733070) |
private class DeconstructionVariable | ||
{ | ||
public BoundExpression Single; | ||
public ImmutableArray<DeconstructionVariable>? Nested; |
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.
Consider using non-nullable ImmutableArray<DeconstructionVariable>
where the unset value is default(Immutable<DeconstructionVariable>)
.
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.
There is a type loader bug that would cause a struct S1 containing ImmutableArray< S1 > be rejected as having a layout cycle (there is not real cycle though since IA wraps a ref array)
CLR knows about this bug, but it is too risky area to fix right now.
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.
Done.
@AlekseyTs @cston I pushed a change that uses |
@AlekseyTs @cston Please let me know if ok to merge. Thanks |
TypeSymbol lhsAsTuple = TupleTypeSymbol.Create(locationOpt: null, elementTypes: lhsTypes, elementLocations: default(ImmutableArray<Location>), elementNames: default(ImmutableArray<string>), compilation: Compilation, diagnostics: diagnostics); | ||
var typedRHS = GenerateConversionForAssignment(lhsAsTuple, boundRHS, diagnostics); | ||
public BoundExpression Single; | ||
public ImmutableArray<DeconstructionVariable> Nested; |
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.
readonly
for both fields.
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.
Done
LGTM |
LGTM, modulo the fact that |
Merged. Thanks for the review and feedback. |
Adding support for nested deconstruction-assignments, such as
(x, (y, z)) = M();
or(x, (y, z)) = (1, (2, 3));
.The bound node now contains:
Note conversions are still coupled with assignments, but I have a work item (in #11299) to do all conversions first then all assignments.
CC @dotnet/roslyn-compiler for review.