Skip to content
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-declaration parsing for local declaration, for and foreach #12104

Merged
merged 13 commits into from
Jun 24, 2016

Conversation

jcouv
Copy link
Member

@jcouv jcouv commented Jun 20, 2016

Adds parsing for three deconstruction-declaration contexts. Other contexts (such as let or from will be added later).

@dotnet/roslyn-compiler for review. Thanks

// All those are parsed as a LocalDeclarationStatement, except that its VariableDeclaration is extended to hold a DeconstructionDeclaration
// DeconstructionDeclaration is DeconstructionVariables + equalsToken + expression
(Int32 a, Int64 b) = foo;
((Int32 a, Int64 b), Int32 c) = foo;
var (a, b) = foo;
var ((a, b), c) = foo;
(Int32 x, var (y, z)) = foo; // var syntax inside list syntax

// This is still a method call
var(a, b);

// ForStatement with the VariableDeclaration holding a DeconstructionDeclaration
for ((Int32 x, Int64 y) = foo; ; ) { }
for (var (x, y) = foo; ; ) { }

// Foreach statement which is extended to hold DeconstructionVariables
foreach ((int x, var y) in foo) { }
foreach (var (x, y) in foo) { }

Note 1: because my VS is busted, I expect some public API errors. I will fix that before checking in.

Note 2: this change includes a copy of Aleksey's recent change in outvar branch to support Internal="true" in Syntax.xml, which will help maintain a backwards compatible public API.

Issue #11299

// foreach ( <type> <identifier> in <expr> ) <embedded-statement>
// or
// foreach ( <deconstruction-variables> in <expr> ) <embedded-statement>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name implies to me that it can only be variables. I assume we can have declarations here as well.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed the comment.

@jcouv
Copy link
Member Author

jcouv commented Jun 20, 2016

Hold off any reviews. From discussion with Cyrus and Aleksey, I'm going to remove the terminals I introduced (to represent "type id" or "id") and use VariableDeclaration instead.

@jcouv
Copy link
Member Author

jcouv commented Jun 21, 2016

@dotnet/roslyn-compiler This is ready to review again.

Two examples:

  1. var (x, (y, z)) = expression gets parsed as a VariableDeclaration with type=var, no regular declarators, and the new deconstruction declarator holding the rest.
    That deconstruction declarator has two variables, each which is a VariableDeclaration where type is null.
    For the first one, the x is inside the regular declarator.
    For the second one, the two variables are inside the deconstruction declarator.
  2. (int x, int y) = expression gets parsed as a VariableDeclaration with no type, no regular declarators, and the deconstruction declarator holding everything.
    That deconstruction declarator has two variables, each which are held as a VariableDeclaration with type=int and the name of the variable inside the regular declarator.

To recap, VariableDeclaration is used in four ways:

  1. type is var, declarator=null and deconstruction is set. Example: var (...) = ...
  2. type is null, declarator=null and deconstruction is set. Example: (int x, int y)
  3. type is set, declarator is set with one element with just a name and deconstruction is null, as before. Example: int x in (int x, int y) = ...
  4. type is null, declarator is set with one element with just a name and deconstruction is null. Example: y in var (x, y) = ...


this.Reset(ref resetPoint);
if ((object)decl == null)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor point: CSharpSyntaxNode does not define == so the cast to object is unnecessary.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed here and other similar instances below. Thanks

@jcouv
Copy link
Member Author

jcouv commented Jun 21, 2016

Just pushed a PR addressing Chuck and Cyrus's feedback.
It removes the new SyntaxKinds, factors ParseDeconstructionListForm and ParseDeconstructionIdentifiers, removes the Internal="true" (and supporting source generation code), and some smaller things.


if (this.CurrentToken.Kind != SyntaxKind.CloseParenToken)
{
VariableDeclarationSyntax variable;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

variable declaration can be moved inside while.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

return null;
}

return CheckFeatureAvailability(result, MessageID.IDS_FeatureTuples);
Copy link
Contributor

@AlekseyTs AlekseyTs Jun 23, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add tests for this check, positive and negative. #Resolved

Copy link
Member Author

@jcouv jcouv Jun 23, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added CSharp6 test. Positive tests will be easier once I have some binding, so they will be added in subsequent PRs.

@jcouv
Copy link
Member Author

jcouv commented Jun 23, 2016

This change to public API is not ready yet. I have more changes coming.

@jcouv
Copy link
Member Author

jcouv commented Jun 23, 2016

Ok, the latest commit I pushed provides a more reasonable public API. If anything, some APIs could be added for convenience.

;

for_statement
: 'for' '(' for_initializer? ';' for_condition? ';' for_iterator? ')' embedded_statement
;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Has for_statement changed or is the same as without deconstruction variables?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the grammar, I kept for_statement as before. The difference appears below, in for_initializer.

@cston
Copy link
Member

cston commented Jun 24, 2016

What kind of parse errors do we report for contexts where deconstruct is not allowed? For instance using ((x, y) = F()) { ... }. Is it necessary to report good errors in these cases?

@cston
Copy link
Member

cston commented Jun 24, 2016

LGTM

@@ -1809,11 +1809,29 @@
<Kind Name="SemicolonToken"/>
</Field>
</Node>
<Node Name="VariableDeclarationSyntax" Base="CSharpSyntaxNode">

<Node Name="VariableDeconstructionDeclaratorSyntax" Base="CSharpSyntaxNode" AvoidAutoCreation="true" InternalConstructor="true">
Copy link
Contributor

@AlekseyTs AlekseyTs Jun 24, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this say InternalFactory rather than constructor? #Resolved

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. Renamed.

@jcouv
Copy link
Member Author

jcouv commented Jun 24, 2016

@cston, I will take a note on your question (should we report errors for un-supported contexts?).

@@ -117,6 +119,20 @@ Microsoft.CodeAnalysis.CSharp.Syntax.TupleTypeSyntax.Update(Microsoft.CodeAnalys
Microsoft.CodeAnalysis.CSharp.Syntax.TupleTypeSyntax.WithCloseParenToken(Microsoft.CodeAnalysis.SyntaxToken closeParenToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.TupleTypeSyntax
Microsoft.CodeAnalysis.CSharp.Syntax.TupleTypeSyntax.WithElements(Microsoft.CodeAnalysis.SeparatedSyntaxList<Microsoft.CodeAnalysis.CSharp.Syntax.TupleElementSyntax> elements) -> Microsoft.CodeAnalysis.CSharp.Syntax.TupleTypeSyntax
Microsoft.CodeAnalysis.CSharp.Syntax.TupleTypeSyntax.WithOpenParenToken(Microsoft.CodeAnalysis.SyntaxToken openParenToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.TupleTypeSyntax
Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeclarationSyntax.Deconstruction.get -> Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeconstructionDeclaratorSyntax
Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeclarationSyntax.WithDeconstruction(Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeconstructionDeclaratorSyntax deconstruction) -> Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeclarationSyntax
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would expect this method to remove regular variables and even type when it has an incompatible value. Does it?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Null input should probably be disallowed as well.


In reply to: 68451172 [](ancestors = 68451172)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An existing VariableDeclarationSyntax.WithVariables should probably be also adjusted accordingly.


In reply to: 68451298 [](ancestors = 68451298,68451172)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added two work items to track this:

  • Add validation to factory methods (only allow creating valid combinations with reasonable-looking children)
  • Add validation logic or erasure to WithXYZ methods

Thanks for raising the questions.

@AlekseyTs
Copy link
Contributor

LGTM

@jcouv
Copy link
Member Author

jcouv commented Jun 24, 2016

Thanks both for the review and feedback. I'll go ahead with merge.

@jcouv jcouv merged commit 78cb91d into dotnet:features/tuples Jun 24, 2016
@jcouv jcouv deleted the d-declaration branch June 24, 2016 21:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants