-
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 #20749
Conversation
Fixes dotnet#10856 ``` public interface ITupleExpression : IOperation { /// <summary> /// Elements for tuple expression. /// </summary> ImmutableArray<IOperation> Elements { get; } } ```
…e expression and parenting variable declaration so we test the operation tree for tuple conversions.
This PR is revival of #19636, with following extra changes:
|
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 comment
The reason will be displayed to describe this comment to others. Learn more.
Re-opening question from previous PR: tuples don't have constant values.
@CyrusNajmabadi prefered to keep as-is. But I don't see the benefit. #Resolved
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.
I'm fine making them not having constant values.
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.
I'd still remove this logic. Tuples don't have constant values.
In reply to: 126766304 [](ancestors = 126766304)
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.
Sure, I have changed this to be initialized to default(Optional<object>)
{ | ||
static void Main() | ||
{ | ||
/*<bind>*/(int A, int B) t = (1, 2)/*</bind>*/; |
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.
All the tests involve literals (which get individually converted). I'd suggest also testing with typed expressions.
int a = 1;
int b = 2;
(long, long) t = (a, b);
I expect to see a tuple with type (int, int), which is converted to (long, long). I'm not sure how such tuple conversion is represented in IOperation. #Resolved
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.
Sure, will add tests.
ILiteralExpression (Text: 1) (OperationKind.LiteralExpression, Type: System.Int32, Constant: 1) (Syntax: '1') | ||
"; | ||
var expectedDiagnostics = new DiagnosticDescription[] { | ||
// CS0266: Cannot implicitly convert type 'int' to 'uint'. An explicit conversion exists (are you missing a cast?) |
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.
I don't think the diagnostics are interesting here. Consider x = 0; y = 0;
in Deconstruct
. Or simply throw null;
. #Resolved
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.
Sure, done.
/// <summary> | ||
/// Elements for tuple expression. | ||
/// </summary> | ||
ImmutableArray<IOperation> Elements { get; } |
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.
This is a general comment beyond this PR, but I'm concerned about materializing more data structures to represent existing information. I would have expected IOperation to be much more "view-like". #Resolved
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.
It wsa an early decision we consciously made. There are negatives to the materialization approach, but it puts us in a good space in terms of defining the tree and getting a good test infrastructure in place for it. We can then optimize it later as necessary as an implementation detail. #Resolved
string expectedOperationTree = @" | ||
IOperation: (OperationKind.None) (Syntax: '(uint x, ui ... Point(0, 1)') | ||
Children(2): ITupleExpression (OperationKind.TupleExpression, Type: (System.UInt32 x, System.UInt32 y)) (Syntax: '(uint x, uint y)') | ||
Elements(2): ILocalReferenceExpression: x (OperationKind.LocalReferenceExpression, Type: System.UInt32) (Syntax: 'uint x') |
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.
Was there a discussion about how to represent declaration expressions in IOperation? I think the bound nodes have a flag to signify that those aren't just references to locals, but actually declaring locals. #Resolved
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.
Filed #20798 to bring this up in the next design meeting.
IVariableDeclaration (1 variables) (OperationKind.VariableDeclaration) (Syntax: 'C t = (0, n ... *</bind>*/;') | ||
Variables: Local_1: C t | ||
Initializer: IConversionExpression (ConversionKind.OperatorMethod, Implicit) (OperatorMethod: C C.op_Implicit((System.Int32, System.String) x)) (OperationKind.ConversionExpression, Type: C) (Syntax: '(0, null)') | ||
IConversionExpression (ConversionKind.CSharp, Implicit) (OperationKind.ConversionExpression, Type: (System.Int32, System.String)) (Syntax: '(0, null)') |
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.
@VSadov, do we expect a conversion here?
} | ||
|
||
[Fact, WorkItem(10856, "https://github.com/dotnet/roslyn/issues/10856")] | ||
public void TupleExpression_Deconstruction() |
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.
TupleExpression_Deconstruction [](start = 20, length = 30)
Consider adding a test for deconstruction-foreach: foreach (var (x, y) in new Point[] { new Point(0, 1) }) { ... }
#Resolved
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.
It seems like no IOperation is exposed for the deconstruction inside foreach, we just expose the IArrayCreationExpression on the right. I will file an issue to track this bug.
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.
Filed #20889
It would have been preferable to continue on the old PR, to maintain comment history. In reply to: 314213234 [](ancestors = 314213234) |
Yes, but I had accidentally created my base branch for that PR on the dotnet upstream, instead of my own fork and GitHub didn't allow me to change the base fork on an existing PR. |
} | ||
|
||
/// <summary> | ||
/// Represents a C# try or a VB Try statement. |
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.
tuple
rather than try
.
} | ||
|
||
[Fact, WorkItem(10856, "https://github.com/dotnet/roslyn/issues/10856")] | ||
public void TupleExpression_NamedElementsInTupleType_ParentVariableDeclaration() |
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.
Do we need separate tests for initializer and _ParentVariableDeclaration
in each case? Would one _ParentVariableDeclaration
test be sufficient for declarations?
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.
This was explicitly requested by Aleksey in the original PR so that we test conversions.
End Sub | ||
|
||
<Fact, WorkItem(10856, "https://github.com/dotnet/roslyn/issues/10856")> | ||
Public Sub TupleExpression_ImplicitConversionFromNull_ParentVaraibleDeclaration() |
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.
Variable
LGTM |
Ping any further feedback @jcouv? I am going to resolve the merge conflicts and fix all the added unit tests due to dumper test change. |
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.
LGTM
Fixes #10856