diff --git a/docs/features/deconstruction.md b/docs/features/deconstruction.md index 93d4a303a1837..0a10068f2cb20 100644 --- a/docs/features/deconstruction.md +++ b/docs/features/deconstruction.md @@ -121,61 +121,63 @@ Note that tuples (`System.ValueTuple`) don't need to invoke Deconstruct. declaration_statement : local_variable_declaration ';' | local_constant_declaration ';' - | local_variable_combo_declaration ';' // new ; -local_variable_combo_declaration - : local_variable_combo_declaration_lhs '=' expression +local_variable_declaration + : local_variable_type local_variable_declarators + | deconstruction_declaration // new + ; -local_variable_combo_declaration_lhs - : 'var' '(' identifier_list ')' - | '(' local_variable_list ')' - ; +deconstruction_declaration // new + : deconstruction_variables '=' expression + ; -identifier_list - : identifier ',' identifier - | identifier_list ',' identifier - ; +deconstuction_variables + : '(' deconstuction_variables_nested (',' deconstuction_variables_nested)* ')' + | 'var' deconstruction_identifiers + ; -local_variable_list - : local_variable_type identifier ',' local_variable_type identifier - | local_variable_list ',' local_variable_type identifier - ; +deconstuction_variables_nested // new + : deconstuction_variables + | type identifier + ; + +deconstruction_identifiers + : '(' deconstruction_identifiers_nested (',' deconstruction_identifiers_nested)* ')' + ; + +deconstruction_identifiers_nested // new + : deconstruction_identifiers + | identifier + ; foreach_statement : 'foreach' '(' local_variable_type identifier 'in' expression ')' embedded_statement - | 'foreach' '(' local_variable_combo_declaration_lhs 'in' expression ')' embedded_statement // new + | 'foreach' '(' deconstruction_variables 'in' expression ')' embedded_statement // new + ; + +for_statement + : 'for' '(' for_initializer? ';' for_condition? ';' for_iterator? ')' embedded_statement ; for_initializer : local_variable_declaration - | local_variable_combo_declaration // new + | deconstruction_declaration // new | statement_expression_list ; let_clause : 'let' identifier '=' expression - | 'let' '(' identifier_list ')' '=' expression // new + | 'let' deconstruction_identifiers '=' expression // new ; -from_clause // not sure +from_clause : 'from' type? identifier 'in' expression - ; - -join_clause // not sure - : 'join' type? identifier 'in' expression 'on' expression 'equals' expression - ; - -join_into_clause // not sure - : 'join' type? identifier 'in' expression 'on' expression 'equals' expression 'into' identifier - ; - -constant_declarator // not sure - : identifier '=' constant_expression + | 'from' deconstuction_variables 'in' expression // new + | 'from' deconstruction_identifiers 'in' expression // new ; ``` -Treat deconstruction of a tuple into new variables as a new kind of node (not AssignmentExpression). It would pick up the behavior of each contexts where new variables can be declared (TODO: need to list). For instance, in LINQ, new variables go into a transparent identifiers. It is seen as deconstructing into separate variables (we don't introduce transparent identifiers in contexts where they didn't exist previously). diff --git a/src/Compilers/CSharp/Portable/CSharpCodeAnalysis.csproj b/src/Compilers/CSharp/Portable/CSharpCodeAnalysis.csproj index 64b5cb82e0b92..1ef7fad2daa88 100644 --- a/src/Compilers/CSharp/Portable/CSharpCodeAnalysis.csproj +++ b/src/Compilers/CSharp/Portable/CSharpCodeAnalysis.csproj @@ -760,6 +760,7 @@ + @@ -854,6 +855,7 @@ + diff --git a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs index bdd7cafaa8466..cdd7a78d41ece 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs +++ b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs @@ -3103,6 +3103,15 @@ internal static string ERR_DeconstructRequiresExpression { } } + /// + /// Looks up a localized string similar to Deconstruction must contain at least two variables.. + /// + internal static string ERR_DeconstructTooFewElements { + get { + return ResourceManager.GetString("ERR_DeconstructTooFewElements", resourceCulture); + } + } + /// /// Looks up a localized string similar to Cannot deconstruct a tuple of '{0}' elements into '{1}' variables.. /// @@ -10493,6 +10502,15 @@ internal static string TypeArgumentCannotBeNull { } } + /// + /// Looks up a localized string similar to The type must be 'var'.. + /// + internal static string TypeMustBeVar { + get { + return ResourceManager.GetString("TypeMustBeVar", resourceCulture); + } + } + /// /// Looks up a localized string similar to Use Microsoft.CodeAnalysis.CSharp.SyntaxFactory.Literal to create numeric literal tokens.. /// diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index 74bf5c3edab53..7eb9c72232da4 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -4896,4 +4896,10 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Cannot deconstruct dynamic objects. + + Deconstruction must contain at least two variables. + + + The type must be 'var'. + \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs index 97eae9e0245da..959135d8b4027 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs @@ -1398,5 +1398,6 @@ internal enum ErrorCode ERR_DeconstructRequiresExpression = 8210, ERR_DeconstructWrongCardinality = 8211, ERR_CannotDeconstructDynamic = 8212, + ERR_DeconstructTooFewElements = 8213, } } diff --git a/src/Compilers/CSharp/Portable/GlobalSuppressions.cs b/src/Compilers/CSharp/Portable/GlobalSuppressions.cs index 36201f1e58362..5bea60c95810f 100644 --- a/src/Compilers/CSharp/Portable/GlobalSuppressions.cs +++ b/src/Compilers/CSharp/Portable/GlobalSuppressions.cs @@ -10,4 +10,9 @@ [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0027:Public API with optional parameter(s) should have the most parameters amongst its public overloads.", Justification = "", Scope = "member", Target = "~M:Microsoft.CodeAnalysis.CSharp.SyntaxFactory.WhenClause(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax)~Microsoft.CodeAnalysis.CSharp.Syntax.WhenClauseSyntax")] [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0027:Public API with optional parameter(s) should have the most parameters amongst its public overloads.", Justification = "", Scope = "member", Target = "~M:Microsoft.CodeAnalysis.CSharp.SyntaxFactory.IncompleteMember(Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax)~Microsoft.CodeAnalysis.CSharp.Syntax.IncompleteMemberSyntax")] [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0027:Public API with optional parameter(s) should have the most parameters amongst its public overloads.", Justification = "", Scope = "member", Target = "~M:Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ReturnStatement(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax)~Microsoft.CodeAnalysis.CSharp.Syntax.ReturnStatementSyntax")] - +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0027:Public API with optional parameter(s) should have the most parameters amongst its public overloads.", Justification = "", Scope = "member", Target = "~M:Microsoft.CodeAnalysis.CSharp.SyntaxFactory.DeconstructionVariablesVar(Microsoft.CodeAnalysis.CSharp.Syntax.TupleExpressionSyntax)~Microsoft.CodeAnalysis.CSharp.Syntax.DeconstructionVariablesVarSyntax")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0027:Public API with optional parameter(s) should have the most parameters amongst its public overloads.", Justification = "", Scope = "member", Target = "~M:Microsoft.CodeAnalysis.CSharp.SyntaxFactory.LocalDeclarationStatement(Microsoft.CodeAnalysis.SyntaxTokenList)~Microsoft.CodeAnalysis.CSharp.Syntax.LocalDeclarationStatementSyntax")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0027:Public API with optional parameter(s) should have the most parameters amongst its public overloads.", Justification = "", Scope = "member", Target = "~M:Microsoft.CodeAnalysis.CSharp.SyntaxFactory.VariableDeconstructionDeclarator(Microsoft.CodeAnalysis.SeparatedSyntaxList{Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeclarationSyntax})~Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeconstructionDeclaratorSyntax")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0027:Public API with optional parameter(s) should have the most parameters amongst its public overloads.", Justification = "", Scope = "member", Target = "~M:Microsoft.CodeAnalysis.CSharp.SyntaxFactory.VariableDeclaration(Microsoft.CodeAnalysis.SeparatedSyntaxList{Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeclaratorSyntax})~Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeclarationSyntax")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0027:Public API with optional parameter(s) should have the most parameters amongst its public overloads.", Justification = "", Scope = "member", Target = "~M:Microsoft.CodeAnalysis.CSharp.SyntaxFactory.FieldDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeclarationSyntax)~Microsoft.CodeAnalysis.CSharp.Syntax.FieldDeclarationSyntax")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0027:Public API with optional parameter(s) should have the most parameters amongst its public overloads.", Justification = "", Scope = "member", Target = "~M:Microsoft.CodeAnalysis.CSharp.SyntaxFactory.EventFieldDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeclarationSyntax)~Microsoft.CodeAnalysis.CSharp.Syntax.EventFieldDeclarationSyntax")] \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs index 2370f52437f80..ad5839511da97 100644 --- a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs +++ b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Linq; using System.Threading; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.Text; @@ -4373,7 +4374,7 @@ private MemberDeclarationSyntax ParseFixedSizeBufferDeclaration( return _syntaxFactory.FieldDeclaration( attributes, modifiers.ToTokenList(), - _syntaxFactory.VariableDeclaration(type, variables), + _syntaxFactory.VariableDeclaration(type, variables, deconstruction: null), semicolon); } finally @@ -4520,7 +4521,7 @@ private FieldDeclarationSyntax ParseNormalFieldDeclaration( return _syntaxFactory.FieldDeclaration( attributes, modifiers.ToTokenList(), - _syntaxFactory.VariableDeclaration(type, variables), + _syntaxFactory.VariableDeclaration(type, variables, deconstruction: null), semicolon); } finally @@ -4567,7 +4568,7 @@ private MemberDeclarationSyntax ParseEventFieldDeclaration( attributes, modifiers.ToTokenList(), eventToken, - _syntaxFactory.VariableDeclaration(type, variables), + _syntaxFactory.VariableDeclaration(type, variables, deconstruction: null), semicolon); } finally @@ -5055,7 +5056,7 @@ private FieldDeclarationSyntax ParseConstantFieldDeclaration(SyntaxListBuilder in ) + // or + // foreach ( in ) SyntaxToken @foreach; @@ -7868,16 +7894,22 @@ private ForEachStatementSyntax ParseForEachStatement() var openParen = this.EatToken(SyntaxKind.OpenParenToken); - var type = this.ParseType(false); - SyntaxToken name; - if (this.CurrentToken.Kind == SyntaxKind.InKeyword) - { - name = this.ParseIdentifierToken(); - name = this.AddError(name, ErrorCode.ERR_BadForeachDecl); - } - else + var deconstruction = TryParseDeconstructionDeclaration(withEquals: false); + + TypeSyntax type = null; + SyntaxToken name = null; + if (deconstruction == null) { - name = this.ParseIdentifierToken(); + type = this.ParseType(false); + if (this.CurrentToken.Kind == SyntaxKind.InKeyword) + { + name = this.ParseIdentifierToken(); + name = this.AddError(name, ErrorCode.ERR_BadForeachDecl); + } + else + { + name = this.ParseIdentifierToken(); + } } var @in = this.EatToken(SyntaxKind.InKeyword, ErrorCode.ERR_InExpected); @@ -7885,7 +7917,7 @@ private ForEachStatementSyntax ParseForEachStatement() var closeParen = this.EatToken(SyntaxKind.CloseParenToken); var statement = this.ParseEmbeddedStatement(true); - return _syntaxFactory.ForEachStatement(@foreach, openParen, type, name, @in, expression, closeParen, statement); + return _syntaxFactory.ForEachStatement(@foreach, openParen, type, name, deconstruction, @in, expression, closeParen, statement); } private GotoStatementSyntax ParseGotoStatement() @@ -8284,11 +8316,22 @@ private LabeledStatementSyntax ParseLabeledStatement() } /// - /// Parses any kind of local declaration statement: local variable, local funcion, or let statement. + /// Parses any kind of local declaration statement: local variable, local function, or deconstruction declaration. /// - /// private StatementSyntax ParseLocalDeclarationStatement() { + VariableDeclarationSyntax deconstruction = TryParseDeconstructionDeclaration(withEquals: true); + if (deconstruction != null) + { + var semicolon = this.EatToken(SyntaxKind.SemicolonToken); + + return _syntaxFactory.LocalDeclarationStatement( + modifiers: default(SyntaxList), + refKeyword: null, + declaration: deconstruction, + semicolonToken: semicolon); + } + var mods = _pool.Allocate(); var variables = _pool.AllocateSeparated(); try @@ -8323,7 +8366,7 @@ private StatementSyntax ParseLocalDeclarationStatement() return _syntaxFactory.LocalDeclarationStatement( mods.ToTokenList(), refKeyword, - _syntaxFactory.VariableDeclaration(type, variables), + _syntaxFactory.VariableDeclaration(type, variables, deconstruction: null), semicolon); } finally @@ -8333,6 +8376,283 @@ private StatementSyntax ParseLocalDeclarationStatement() } } + /// + /// Returns null and resets the pointer if this does not look like a deconstruction-declaration after all. + /// + private VariableDeclarationSyntax TryParseDeconstructionDeclaration(bool withEquals) + { + if (this.CurrentToken.Kind == SyntaxKind.OpenParenToken + || (CurrentToken.IsVar() && this.PeekToken(1).Kind == SyntaxKind.OpenParenToken)) + { + var resetPoint = this.GetResetPoint(); + + try + { + var deconstruction = ParseDeconstructionDeclaration(withEquals); + if (deconstruction == null || !DeconstructionVariableLooksGood(deconstruction, withEquals)) + { + this.Reset(ref resetPoint); + return null; + } + else + { + return deconstruction; + } + + } + finally + { + this.Release(ref resetPoint); + } + } + + return null; + } + + /// + /// Parses a deconstruction-declaration, which can appear in a local-declaration statement or a for statement. + /// Returns null if this does not look like a deconstruction-declaration after all (equal sign missing). + /// + /// The syntax is either var form: `var (deconstruction-declaration, ...) = expression` or list form `(deconstruction-declaration, ...) = expression`. + /// Cannot return null, except at the top-level. + /// + /// Specifies whether to look for and consume the equals sign and the following expression. + /// Specifies whether to parse the terminal form of a deconstruction-declaration (which can't appear at the top-level). + private VariableDeclarationSyntax ParseDeconstructionDeclaration(bool withEquals, bool topLevel = true) + { + Debug.Assert(topLevel || !withEquals); // withEquals can only be set at the top-level + + VariableDeclarationSyntax result; + if (this.CurrentToken.IsVar() && this.PeekToken(1).Kind == SyntaxKind.OpenParenToken) + { + // parses `var (...) = expression` form + result = ParseDeconstructionVarForm(withEquals); + } + else if (this.CurrentToken.Kind == SyntaxKind.OpenParenToken) + { + // parses `(...) = expression` form + result = ParseDeconstructionList(withEquals, justIdentifiers: false); + } + else if (!topLevel) + { + // parses `type id` part + result = ParseDeconstructionTypeIdPart(); + } + else + { + return null; + } + + return CheckFeatureAvailability(result, MessageID.IDS_FeatureTuples); + } + + /// + /// Parses `(..., ..., ...)` where each part is deconstruction variables (such as `type id` or `var (..., ...)` or another list `(..., ..., ...)`). + /// Never returns null. + /// + private VariableDeclarationSyntax ParseDeconstructionList(bool withEquals, bool justIdentifiers) + { + var list = _pool.AllocateSeparated(); + + try + { + var openParen = this.EatToken(SyntaxKind.OpenParenToken); + + if (this.CurrentToken.Kind != SyntaxKind.CloseParenToken) + { + while (true) + { + VariableDeclarationSyntax variable; + + if (justIdentifiers) + { + variable = ParseDeconstructionIdentifierOrIdentifiersParts(withEquals: false); + } + else + { + variable = ParseDeconstructionDeclaration(withEquals: false, topLevel: false); + } + + Debug.Assert(variable != null); + list.Add(variable); + + if (this.CurrentToken.Kind != SyntaxKind.CommaToken) + { + break; + } + + var comma = this.EatToken(SyntaxKind.CommaToken); + list.AddSeparator(comma); + } + } + + var closeParen = this.EatToken(SyntaxKind.CloseParenToken); + + SyntaxToken equals = null; + ExpressionSyntax expression = null; + if (withEquals) + { + equals = this.EatToken(SyntaxKind.EqualsToken); + expression = this.ParseExpressionCore(); + } + + var deconstruction = _syntaxFactory.VariableDeconstructionDeclarator(openParen, list, closeParen, equals, expression); + var result = _syntaxFactory.VariableDeclaration(type: null, variables: default(SeparatedSyntaxList), deconstruction: deconstruction); + + if (!result.ContainsDiagnostics && list.Count < 2) + { + result = this.AddError(result, ErrorCode.ERR_DeconstructTooFewElements); + } + + return result; + } + finally + { + _pool.Free(list); + } + } + + /// + /// Parses the var form of deconstruction. For instance, `var (x, y) = ...` + /// Never returns null. + /// + private VariableDeclarationSyntax ParseDeconstructionVarForm(bool withEquals) + { + Debug.Assert(this.CurrentToken.IsVar()); + + var varType = ParseType(parentIsParameter: false); + var identifiers = ParseDeconstructionList(withEquals, justIdentifiers: true); + + return _syntaxFactory.VariableDeclaration(varType, default(SeparatedSyntaxList), identifiers.Deconstruction); + } + + /// + /// Parses both `id` and `(id, ...)` in a deconstruction-declaration. + /// Never returns null. + /// + private VariableDeclarationSyntax ParseDeconstructionIdentifierOrIdentifiersParts(bool withEquals) + { + if (this.CurrentToken.Kind == SyntaxKind.OpenParenToken) + { + return ParseDeconstructionList(withEquals: false, justIdentifiers: true); + } + else + { + return ParseDeconstructionIdPart(); + } + } + + /// + /// Parses an individual identifier in a deconstruction declaration. For instance, in `var (id, id) = ...` + /// Never returns null. + /// + private VariableDeclarationSyntax ParseDeconstructionIdPart() + { + var identifier = ParseIdentifierToken(); + var declarator = _syntaxFactory.VariableDeclarator(identifier, null, null); + return _syntaxFactory.VariableDeclaration( + type: null, + variables: SyntaxFactory.SeparatedList(declarator), + deconstruction: null); + } + + /// + /// Parses an individual type and identifier in a deconstruction declaration. For instance, in `(type id, type id) = ...` + /// Never returns null. + /// + private VariableDeclarationSyntax ParseDeconstructionTypeIdPart() + { + var type = ParseType(parentIsParameter: false); + var identifier = ParseIdentifierToken(); + + var declarator = _syntaxFactory.VariableDeclarator(identifier, null, null); + return _syntaxFactory.VariableDeclaration( + type: type, + variables: SyntaxFactory.SeparatedList(declarator), + deconstruction: null); + } + + /// + /// Check ahead for a deconstruction declaration. This requires at least one good-looking variable and the presence of an equals sign. + /// Doesn't move the cursor. + /// PROTOTYPE(tuples) Can this be done without allocations? + /// + private bool IsPossibleDeconstructionDeclaration() + { + if ((this.CurrentToken.IsVar() && this.PeekToken(1).Kind == SyntaxKind.OpenParenToken) || + this.CurrentToken.Kind == SyntaxKind.OpenParenToken) + { + var resetPoint = this.GetResetPoint(); + try + { + // We don't need to parse the expression following the equals token + var variables = ParseDeconstructionDeclaration(withEquals: false); + var equalsToken = this.EatToken(SyntaxKind.EqualsToken); + + // We just need the equals token and one other confirmation that this is a deconstruction syntax + return DeconstructionVariableLooksGood(variables, withEquals: false) && !equalsToken.IsMissing; + } + finally + { + this.Reset(ref resetPoint); + this.Release(ref resetPoint); + } + } + else + { + return false; + } + } + + /// + /// Returns true if one distinct clue is found that this is intended as deconstruction variables, and the equals sign is as expected. + /// + private static bool DeconstructionVariableLooksGood(VariableDeclarationSyntax node, bool withEquals = true) + { + if (node == null) + { + return false; + } + + if (withEquals && node.Deconstruction != null && node.Deconstruction.EqualsToken.IsMissing) + { + return false; + } + + if (node.Type != null) + { + if (node.Type.Kind == SyntaxKind.IdentifierName && ((IdentifierNameSyntax)node.Type).Identifier.IsVar() + && node.Deconstruction != null && !node.Deconstruction.OpenParenToken.IsMissing && !node.Deconstruction.CloseParenToken.IsMissing) + { + // `var (..., ....)` with var and both parens present + return true; + } + + if (!node.Type.IsMissing && node.Variables.Count == 1 && !node.Variables[0].Identifier.IsMissing) + { + // `type id` with both type and id present + return true; + } + } + else + { + if (node.Variables.Count == 0 && node.Deconstruction != null) + { + // (..., ...) where one of the elements looks good + int count = node.Deconstruction.Variables.Count; + for (int i = 0; i < count; i++) + { + if (DeconstructionVariableLooksGood(node.Deconstruction.Variables[i], withEquals: false)) + { + return true; + } + } + } + } + + return false; + } + private WhenClauseSyntax ParseWhenClauseOpt() { if (this.CurrentToken.ContextualKind != SyntaxKind.WhenKeyword) @@ -8356,7 +8676,7 @@ private VariableDeclarationSyntax ParseVariableDeclaration() LocalFunctionStatementSyntax localFunction; ParseLocalDeclaration(variables, false, default(SyntaxList), default(SyntaxToken), out type, out localFunction); Debug.Assert(localFunction == null); - var result = _syntaxFactory.VariableDeclaration(type, variables); + var result = _syntaxFactory.VariableDeclaration(type, variables, deconstruction: null); _pool.Free(variables); return result; } diff --git a/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt b/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt index 36114469e6090..92657a0fcec4a 100644 --- a/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt @@ -26,6 +26,8 @@ Microsoft.CodeAnalysis.CSharp.Syntax.DelegateDeclarationSyntax.WithRefKeyword(Mi Microsoft.CodeAnalysis.CSharp.Syntax.EqualsValueClauseSyntax.RefKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken Microsoft.CodeAnalysis.CSharp.Syntax.EqualsValueClauseSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken equalsToken, Microsoft.CodeAnalysis.SyntaxToken refKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax value) -> Microsoft.CodeAnalysis.CSharp.Syntax.EqualsValueClauseSyntax Microsoft.CodeAnalysis.CSharp.Syntax.EqualsValueClauseSyntax.WithRefKeyword(Microsoft.CodeAnalysis.SyntaxToken refKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.EqualsValueClauseSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.ForEachStatementSyntax.DeconstructionVariables.get -> Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeclarationSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.ForEachStatementSyntax.WithDeconstructionVariables(Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeclarationSyntax deconstructionVariables) -> Microsoft.CodeAnalysis.CSharp.Syntax.ForEachStatementSyntax Microsoft.CodeAnalysis.CSharp.Syntax.ForStatementSyntax.RefKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken Microsoft.CodeAnalysis.CSharp.Syntax.ForStatementSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken forKeyword, Microsoft.CodeAnalysis.SyntaxToken openParenToken, Microsoft.CodeAnalysis.SyntaxToken refKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeclarationSyntax declaration, Microsoft.CodeAnalysis.SeparatedSyntaxList initializers, Microsoft.CodeAnalysis.SyntaxToken firstSemicolonToken, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax condition, Microsoft.CodeAnalysis.SyntaxToken secondSemicolonToken, Microsoft.CodeAnalysis.SeparatedSyntaxList incrementors, Microsoft.CodeAnalysis.SyntaxToken closeParenToken, Microsoft.CodeAnalysis.CSharp.Syntax.StatementSyntax statement) -> Microsoft.CodeAnalysis.CSharp.Syntax.ForStatementSyntax Microsoft.CodeAnalysis.CSharp.Syntax.ForStatementSyntax.WithRefKeyword(Microsoft.CodeAnalysis.SyntaxToken refKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.ForStatementSyntax @@ -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 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 +Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeconstructionDeclaratorSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeconstructionDeclaratorSyntax.AddVariables(params Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeclarationSyntax[] items) -> Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeconstructionDeclaratorSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeconstructionDeclaratorSyntax.CloseParenToken.get -> Microsoft.CodeAnalysis.SyntaxToken +Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeconstructionDeclaratorSyntax.EqualsToken.get -> Microsoft.CodeAnalysis.SyntaxToken +Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeconstructionDeclaratorSyntax.OpenParenToken.get -> Microsoft.CodeAnalysis.SyntaxToken +Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeconstructionDeclaratorSyntax.Value.get -> Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeconstructionDeclaratorSyntax.Variables.get -> Microsoft.CodeAnalysis.SeparatedSyntaxList +Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeconstructionDeclaratorSyntax.WithCloseParenToken(Microsoft.CodeAnalysis.SyntaxToken closeParenToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeconstructionDeclaratorSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeconstructionDeclaratorSyntax.WithEqualsToken(Microsoft.CodeAnalysis.SyntaxToken equalsToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeconstructionDeclaratorSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeconstructionDeclaratorSyntax.WithOpenParenToken(Microsoft.CodeAnalysis.SyntaxToken openParenToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeconstructionDeclaratorSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeconstructionDeclaratorSyntax.WithValue(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax value) -> Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeconstructionDeclaratorSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeconstructionDeclaratorSyntax.WithVariables(Microsoft.CodeAnalysis.SeparatedSyntaxList variables) -> Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeconstructionDeclaratorSyntax Microsoft.CodeAnalysis.CSharp.Syntax.WhenClauseSyntax Microsoft.CodeAnalysis.CSharp.Syntax.WhenClauseSyntax.Condition.get -> Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax Microsoft.CodeAnalysis.CSharp.Syntax.WhenClauseSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken whenKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax condition) -> Microsoft.CodeAnalysis.CSharp.Syntax.WhenClauseSyntax @@ -134,6 +150,7 @@ Microsoft.CodeAnalysis.CSharp.SyntaxKind.ReplaceKeyword = 8439 -> Microsoft.Code Microsoft.CodeAnalysis.CSharp.SyntaxKind.TupleElement = 8926 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.TupleExpression = 8927 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.TupleType = 8925 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind +Microsoft.CodeAnalysis.CSharp.SyntaxKind.VariableDeconstructionDeclarator = 8928 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.WhenClause = 9013 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitCasePatternSwitchLabel(Microsoft.CodeAnalysis.CSharp.Syntax.CasePatternSwitchLabelSyntax node) -> Microsoft.CodeAnalysis.SyntaxNode override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitConstantPattern(Microsoft.CodeAnalysis.CSharp.Syntax.ConstantPatternSyntax node) -> Microsoft.CodeAnalysis.SyntaxNode @@ -144,6 +161,7 @@ override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitOriginalExpress override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitTupleElement(Microsoft.CodeAnalysis.CSharp.Syntax.TupleElementSyntax node) -> Microsoft.CodeAnalysis.SyntaxNode override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitTupleExpression(Microsoft.CodeAnalysis.CSharp.Syntax.TupleExpressionSyntax node) -> Microsoft.CodeAnalysis.SyntaxNode override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitTupleType(Microsoft.CodeAnalysis.CSharp.Syntax.TupleTypeSyntax node) -> Microsoft.CodeAnalysis.SyntaxNode +override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitVariableDeconstructionDeclarator(Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeconstructionDeclaratorSyntax node) -> Microsoft.CodeAnalysis.SyntaxNode override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitWhenClause(Microsoft.CodeAnalysis.CSharp.Syntax.WhenClauseSyntax node) -> Microsoft.CodeAnalysis.SyntaxNode override Microsoft.CodeAnalysis.CSharp.Syntax.CasePatternSwitchLabelSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor visitor) -> void override Microsoft.CodeAnalysis.CSharp.Syntax.CasePatternSwitchLabelSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor visitor) -> TResult @@ -165,6 +183,8 @@ override Microsoft.CodeAnalysis.CSharp.Syntax.TupleExpressionSyntax.Accept(Micro override Microsoft.CodeAnalysis.CSharp.Syntax.TupleExpressionSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor visitor) -> TResult override Microsoft.CodeAnalysis.CSharp.Syntax.TupleTypeSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor visitor) -> void override Microsoft.CodeAnalysis.CSharp.Syntax.TupleTypeSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor visitor) -> TResult +override Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeconstructionDeclaratorSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor visitor) -> void +override Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeconstructionDeclaratorSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor visitor) -> TResult override Microsoft.CodeAnalysis.CSharp.Syntax.WhenClauseSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor visitor) -> void override Microsoft.CodeAnalysis.CSharp.Syntax.WhenClauseSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor visitor) -> TResult static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetDeclaredSymbol(this Microsoft.CodeAnalysis.SemanticModel semanticModel, Microsoft.CodeAnalysis.CSharp.Syntax.DeclarationPatternSyntax declarationSyntax, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.ISymbol @@ -201,6 +221,8 @@ static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.TupleExpression(Microsoft.Cod static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.TupleExpression(Microsoft.CodeAnalysis.SyntaxToken openParenToken, Microsoft.CodeAnalysis.SeparatedSyntaxList arguments, Microsoft.CodeAnalysis.SyntaxToken closeParenToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.TupleExpressionSyntax static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.TupleType(Microsoft.CodeAnalysis.SeparatedSyntaxList elements = default(Microsoft.CodeAnalysis.SeparatedSyntaxList)) -> Microsoft.CodeAnalysis.CSharp.Syntax.TupleTypeSyntax static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.TupleType(Microsoft.CodeAnalysis.SyntaxToken openParenToken, Microsoft.CodeAnalysis.SeparatedSyntaxList elements, Microsoft.CodeAnalysis.SyntaxToken closeParenToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.TupleTypeSyntax +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.VariableDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax type, Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeconstructionDeclaratorSyntax deconstructionDeclaration) -> Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeclarationSyntax +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.VariableDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeconstructionDeclaratorSyntax deconstructionDeclaration) -> Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeclarationSyntax static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.WhenClause(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax condition = null) -> Microsoft.CodeAnalysis.CSharp.Syntax.WhenClauseSyntax static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.WhenClause(Microsoft.CodeAnalysis.SyntaxToken whenKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax condition) -> Microsoft.CodeAnalysis.CSharp.Syntax.WhenClauseSyntax virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitCasePatternSwitchLabel(Microsoft.CodeAnalysis.CSharp.Syntax.CasePatternSwitchLabelSyntax node) -> void @@ -212,6 +234,7 @@ virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitOriginalExpressio virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitTupleElement(Microsoft.CodeAnalysis.CSharp.Syntax.TupleElementSyntax node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitTupleExpression(Microsoft.CodeAnalysis.CSharp.Syntax.TupleExpressionSyntax node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitTupleType(Microsoft.CodeAnalysis.CSharp.Syntax.TupleTypeSyntax node) -> void +virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitVariableDeconstructionDeclarator(Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeconstructionDeclaratorSyntax node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitWhenClause(Microsoft.CodeAnalysis.CSharp.Syntax.WhenClauseSyntax node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitCasePatternSwitchLabel(Microsoft.CodeAnalysis.CSharp.Syntax.CasePatternSwitchLabelSyntax node) -> TResult virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitConstantPattern(Microsoft.CodeAnalysis.CSharp.Syntax.ConstantPatternSyntax node) -> TResult @@ -222,4 +245,5 @@ virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitOriginal virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitTupleElement(Microsoft.CodeAnalysis.CSharp.Syntax.TupleElementSyntax node) -> TResult virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitTupleExpression(Microsoft.CodeAnalysis.CSharp.Syntax.TupleExpressionSyntax node) -> TResult virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitTupleType(Microsoft.CodeAnalysis.CSharp.Syntax.TupleTypeSyntax node) -> TResult +virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitVariableDeconstructionDeclarator(Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeconstructionDeclaratorSyntax node) -> TResult virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitWhenClause(Microsoft.CodeAnalysis.CSharp.Syntax.WhenClauseSyntax node) -> TResult \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/Syntax/ForEachStatementSyntax.cs b/src/Compilers/CSharp/Portable/Syntax/ForEachStatementSyntax.cs new file mode 100644 index 0000000000000..5351f6f1735b7 --- /dev/null +++ b/src/Compilers/CSharp/Portable/Syntax/ForEachStatementSyntax.cs @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Microsoft.CodeAnalysis.CSharp.Syntax +{ + public sealed partial class ForEachStatementSyntax : StatementSyntax + { + public ForEachStatementSyntax Update(SyntaxToken forEachKeyword, SyntaxToken openParenToken, TypeSyntax type, SyntaxToken identifier, SyntaxToken inKeyword, ExpressionSyntax expression, SyntaxToken closeParenToken, StatementSyntax statement) + { + return Update(forEachKeyword, openParenToken, type, identifier, null, inKeyword, expression, closeParenToken, statement); + } + } +} diff --git a/src/Compilers/CSharp/Portable/Syntax/Syntax.xml b/src/Compilers/CSharp/Portable/Syntax/Syntax.xml index d0c54bb560b91..8144a04bd29c0 100644 --- a/src/Compilers/CSharp/Portable/Syntax/Syntax.xml +++ b/src/Compilers/CSharp/Portable/Syntax/Syntax.xml @@ -1809,11 +1809,29 @@ - + + + + + + + + + + + + + + + + + - + + + @@ -2033,7 +2051,8 @@ - + + @@ -2041,13 +2060,14 @@ - - + + Gets the identifier. + @@ -2057,6 +2077,7 @@ + @@ -3933,7 +3954,7 @@ -