-
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
Add IOperation support for tuple expressions #19636
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -165,6 +165,9 @@ private static IOperation CreateInternal(BoundNode boundNode) | |
return CreateBoundLabeledStatementOperation((BoundLabeledStatement)boundNode); | ||
case BoundKind.ExpressionStatement: | ||
return CreateBoundExpressionStatementOperation((BoundExpressionStatement)boundNode); | ||
case BoundKind.TupleLiteral: | ||
case BoundKind.ConvertedTupleLiteral: | ||
return CreateBoundTupleExpressionOperation((BoundTupleExpression)boundNode); | ||
default: | ||
var constantValue = ConvertToOptional((boundNode as BoundExpression)?.ConstantValue); | ||
return Operation.CreateOperationNone(boundNode.HasErrors, boundNode.Syntax, constantValue, getChildren: () => GetIOperationChildren(boundNode)); | ||
|
@@ -985,5 +988,15 @@ private static IExpressionStatement CreateBoundExpressionStatementOperation(Boun | |
Optional<object> constantValue = default(Optional<object>); | ||
return new LazyExpressionStatement(expression, isInvalid, syntax, type, constantValue); | ||
} | ||
|
||
private static ITupleExpression CreateBoundTupleExpressionOperation(BoundTupleExpression boundTupleExpression) | ||
{ | ||
Lazy<ImmutableArray<IOperation>> elements = new Lazy<ImmutableArray<IOperation>>(() => GetTupleElements(boundTupleExpression)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This lambda (and all others above) are creating closures. The compiler generally tries to avoid this, so I'm surprised to see this a recurring pattern in this file. Maybe something to consider for a follow-up refactoring as well? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, certainly. Let me file an issue to track all your review comments here.. Thanks! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Filed #19720 |
||
bool isInvalid = boundTupleExpression.HasErrors; | ||
SyntaxNode syntax = boundTupleExpression.Syntax; | ||
ITypeSymbol type = boundTupleExpression.Type; | ||
Optional<object> constantValue = ConvertToOptional(boundTupleExpression.ConstantValue); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think tuple can ever have a constant value. #WontFix There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The bound node will reflect that. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would keep this as is. If tuples could ever become constnat, then this code will continue to work. |
||
return new LazyTupleExpression(elements, isInvalid, syntax, type, constantValue); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -340,6 +340,15 @@ private static ImmutableArray<IVariableDeclaration> GetVariableDeclarationStatem | |
OperationFactory.CreateVariableDeclaration(declaration.LocalSymbol, Create(declaration.InitializerOpt), declaration.Syntax))); | ||
} | ||
|
||
private static readonly ConditionalWeakTable<BoundTupleExpression, object> s_tupleElementsMappings = | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there a reason not to have specific type (as opposed to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @heejaechang? Comment tracked in #19720 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The problem with CWT is that it has a 'class' constraint on the values. But we're storing ImmutableArrays. So we end up needing to box things into object to satisfy the CWT. |
||
new ConditionalWeakTable<BoundTupleExpression, object>(); | ||
|
||
private static ImmutableArray<IOperation> GetTupleElements(BoundTupleExpression boundTupleExpression) | ||
{ | ||
return (ImmutableArray<IOperation>)s_tupleElementsMappings.GetValue(boundTupleExpression, | ||
tupleExpr => tupleExpr.Arguments.SelectAsArray(element => Create(element))); | ||
} | ||
|
||
// TODO: We need to reuse the logic in `LocalRewriter.MakeArguments` instead of using private implementation. | ||
// Also. this implementation here was for the (now removed) API `ArgumentsInParameter`, which doesn't fulfill | ||
// the contract of `ArgumentsInEvaluationOrder` plus it doesn't handle various scenarios correctly even for parameter order, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,8 +23,8 @@ public void M(int x, int y) | |
} | ||
"; | ||
string expectedOperationTree = @" | ||
IOperation: (OperationKind.None) (Syntax: '(x, x + y)') | ||
Children(2): IParameterReferenceExpression: x (OperationKind.ParameterReferenceExpression, Type: System.Int32) (Syntax: 'x') | ||
ITupleExpression (OperationKind.TupleExpression, Type: (System.Int32 x, System.Int32)) (Syntax: '(x, x + y)') | ||
Elements(2): IParameterReferenceExpression: x (OperationKind.ParameterReferenceExpression, Type: System.Int32) (Syntax: 'x') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In terms of formatting, maybe There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, we hope to make that change in the dump format, but it would require updating almost all the IOperation tests. We have it in our backlog though... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
IBinaryOperatorExpression (BinaryOperationKind.IntegerAdd) (OperationKind.BinaryOperatorExpression, Type: System.Int32) (Syntax: 'x + y') | ||
Left: IParameterReferenceExpression: x (OperationKind.ParameterReferenceExpression, Type: System.Int32) (Syntax: 'x') | ||
Right: IParameterReferenceExpression: y (OperationKind.ParameterReferenceExpression, Type: System.Int32) (Syntax: 'y') | ||
|
@@ -66,8 +66,8 @@ public void M(Point point) | |
"; | ||
string expectedOperationTree = @" | ||
IOperation: (OperationKind.None) (Syntax: 'var (x, y) = point') | ||
Children(2): IOperation: (OperationKind.None) (Syntax: 'var (x, y)') | ||
Children(2): ILocalReferenceExpression: x (OperationKind.LocalReferenceExpression, Type: System.Int32) (Syntax: 'x') | ||
Children(2): ITupleExpression (OperationKind.TupleExpression, Type: (System.Int32 x, System.Int32 y)) (Syntax: 'var (x, y)') | ||
Elements(2): ILocalReferenceExpression: x (OperationKind.LocalReferenceExpression, Type: System.Int32) (Syntax: 'x') | ||
ILocalReferenceExpression: y (OperationKind.LocalReferenceExpression, Type: System.Int32) (Syntax: 'y') | ||
IConversionExpression (ConversionKind.Invalid, Implicit) (OperationKind.ConversionExpression, Type: (System.Int32 x, System.Int32 y)) (Syntax: 'point') | ||
IParameterReferenceExpression: point (OperationKind.ParameterReferenceExpression, Type: Point) (Syntax: 'point') | ||
|
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.
Nit: you could omit the type (use
var
) since type is spelled out on the right-hand-side. #ResolvedThere 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.
I have followed the existing pattern used in this file @heejaechang probably we can clean this up for the entire file in one of your refactorings?
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.
Use of
var
is not a requirement. It is the other way around, we forbid use ofvar
in some cases.