diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Deconstruct.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Deconstruct.cs index 945b7521bbedc3e28cab72f78bf5e96d868d2238..6cb4c4db7e3d2b496478a8a39a5118cac591f33f 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Deconstruct.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Deconstruct.cs @@ -174,7 +174,7 @@ private BoundExpression FixTupleLiteral(ArrayBuilder che /// /// The produces a deconstruction step with no Deconstruct method since the tuple already has distinct elements. /// - private static BoundDeconstructionDeconstructStep MakeTupleDeconstructStep( + private BoundDeconstructionDeconstructStep MakeTupleDeconstructStep( BoundDeconstructValuePlaceholder targetPlaceholder, CSharpSyntaxNode syntax, DiagnosticBag diagnostics, @@ -183,7 +183,7 @@ private BoundExpression FixTupleLiteral(ArrayBuilder che Debug.Assert(targetPlaceholder.Type.IsTupleType); var tupleTypes = targetPlaceholder.Type.TupleElementTypes; - SetInferredTypes(variables, tupleTypes); + SetInferredTypes(variables, tupleTypes, diagnostics); if (variables.Count != tupleTypes.Length) { @@ -212,7 +212,7 @@ private BoundExpression FixTupleLiteral(ArrayBuilder che return null; } - SetInferredTypes(variables, outPlaceholders.SelectAsArray(p => p.Type)); + SetInferredTypes(variables, outPlaceholders.SelectAsArray(p => p.Type), diagnostics); return new BoundDeconstructionDeconstructStep(syntax, deconstructInvocation, targetPlaceholder, outPlaceholders); } @@ -220,15 +220,15 @@ private BoundExpression FixTupleLiteral(ArrayBuilder che /// /// Inform the variables about found types. /// - private static void SetInferredTypes(ArrayBuilder variables, ImmutableArray foundTypes) + private void SetInferredTypes(ArrayBuilder variables, ImmutableArray foundTypes, DiagnosticBag diagnostics) { var matchCount = Math.Min(variables.Count, foundTypes.Length); for (int i = 0; i < matchCount; i++) { var variable = variables[i]; - if (!variable.HasNestedVariables && variable.Single.Kind == BoundKind.DeconstructionLocalPendingInference) + if (!variable.HasNestedVariables && variable.Single.Kind == BoundKind.DeconstructionVariablePendingInference) { - BoundLocal local = ((DeconstructionLocalPendingInference)variable.Single).SetInferredType(foundTypes[i], success: true); + BoundExpression local = ((DeconstructionVariablePendingInference)variable.Single).SetInferredType(foundTypes[i], this, diagnostics); variables[i] = new DeconstructionVariable(local, local.Syntax); } } @@ -239,7 +239,7 @@ private static void SetInferredTypes(ArrayBuilder variab /// private void FailRemainingInferences(ArrayBuilder variables, DiagnosticBag diagnostics) { - var count = variables.Count; + int count = variables.Count; for (int i = 0; i < count; i++) { var variable = variables[i]; @@ -249,9 +249,9 @@ private void FailRemainingInferences(ArrayBuilder variab } else { - if (variable.Single.Kind == BoundKind.DeconstructionLocalPendingInference) + if (variable.Single.Kind == BoundKind.DeconstructionVariablePendingInference) { - var local = ((DeconstructionLocalPendingInference)variable.Single).FailInference(this); + BoundExpression local = ((DeconstructionVariablePendingInference)variable.Single).FailInference(this, diagnostics); variables[i] = new DeconstructionVariable(local, local.Syntax); } } @@ -409,11 +409,6 @@ private static TypeSymbol MakeMergedTupleType(ArrayBuilder + /// Prepares locals (or fields in global statement) corresponding to the variables of the declaration. + /// The locals/fields are kept in a tree which captures the nesting of variables. + /// Each local or field is either a simple local or field access (when its type is known) or a deconstruction variable pending inference. + /// The caller is responsible for releasing the nested ArrayBuilders. + /// + private DeconstructionVariable BindDeconstructionDeclarationVariables( + VariableComponentSyntax node, + DiagnosticBag diagnostics) { switch (node.Kind()) { case SyntaxKind.TypedVariableComponent: { var component = (TypedVariableComponentSyntax)node; - return BindDeconstructionDeclarationLocals(component.Type, component.Designation, diagnostics); + return BindDeconstructionDeclarationVariables(component.Type, component.Designation, diagnostics); } case SyntaxKind.ParenthesizedVariableComponent: { @@ -641,7 +644,7 @@ private DeconstructionVariable BindDeconstructionDeclarationLocals(VariableCompo var builder = ArrayBuilder.GetInstance(component.Variables.Count); foreach (var n in component.Variables) { - builder.Add(BindDeconstructionDeclarationLocals(n, diagnostics)); + builder.Add(BindDeconstructionDeclarationVariables(n, diagnostics)); } return new DeconstructionVariable(builder, node); } @@ -650,14 +653,17 @@ private DeconstructionVariable BindDeconstructionDeclarationLocals(VariableCompo } } - private DeconstructionVariable BindDeconstructionDeclarationLocals(TypeSyntax type, VariableDesignationSyntax node, DiagnosticBag diagnostics) + private DeconstructionVariable BindDeconstructionDeclarationVariables( + TypeSyntax type, + VariableDesignationSyntax node, + DiagnosticBag diagnostics) { switch (node.Kind()) { case SyntaxKind.SingleVariableDesignation: { var single = (SingleVariableDesignationSyntax)node; - return new DeconstructionVariable(BindDeconstructionDeclarationLocal(type, single, diagnostics), node); + return new DeconstructionVariable(BindDeconstructionDeclarationVariable(type, single, diagnostics), node); } case SyntaxKind.ParenthesizedVariableDesignation: { @@ -665,7 +671,7 @@ private DeconstructionVariable BindDeconstructionDeclarationLocals(TypeSyntax ty var builder = ArrayBuilder.GetInstance(); foreach (var n in tuple.Variables) { - builder.Add(BindDeconstructionDeclarationLocals(type, n, diagnostics)); + builder.Add(BindDeconstructionDeclarationVariables(type, n, diagnostics)); } return new DeconstructionVariable(builder, node); } @@ -675,30 +681,18 @@ private DeconstructionVariable BindDeconstructionDeclarationLocals(TypeSyntax ty } /// - /// Prepares locals corresponding to the variables of the declaration. - /// The locals are kept in a tree which captures the nesting of variables. - /// Each local is either a simple local (when its type is known) or a deconstruction local pending inference. - /// The caller is responsible for releasing the nested ArrayBuilders. + /// In embedded statements, returns a BoundLocal when the type was explicit. + /// In global statements, returns a BoundFieldAccess when the type was explicit. + /// Otherwise returns a DeconstructionVariablePendingInference when the type is implicit. /// - private ArrayBuilder BindDeconstructionDeclarationLocals(VariableComponentAssignmentSyntax node, TypeSyntax closestTypeSyntax, DiagnosticBag diagnostics) + private BoundExpression BindDeconstructionDeclarationVariable( + TypeSyntax typeSyntax, + SingleVariableDesignationSyntax designation, + DiagnosticBag diagnostics) { - var deconstructionVariable = BindDeconstructionDeclarationLocals(node.VariableComponent, diagnostics); - Debug.Assert(deconstructionVariable.HasNestedVariables); - return deconstructionVariable.NestedVariables; - } - - /// - /// Returns a BoundLocal when the type was explicit, otherwise returns a DeconstructionLocalPendingInference. - /// - private BoundExpression BindDeconstructionDeclarationLocal(TypeSyntax typeSyntax, SingleVariableDesignationSyntax designation, DiagnosticBag diagnostics) - { - var localSymbol = LocateDeclaredVariableSymbol(designation, typeSyntax); - - // Check for variable declaration errors. - // Use the binder that owns the scope for the local because this (the current) binder - // might own nested scope. - bool hasErrors = localSymbol.ScopeBinder.ValidateDeclarationNameConflictsInScope(localSymbol, diagnostics); + SourceLocalSymbol localSymbol = LookupLocal(designation.Identifier); + bool hasErrors = false; bool isVar; bool isConst = false; AliasSymbol alias; @@ -712,11 +706,49 @@ private BoundExpression BindDeconstructionDeclarationLocal(TypeSyntax typeSyntax Error(diagnostics, ErrorCode.ERR_DeconstructionVarFormDisallowsSpecificType, designation); hasErrors = true; } + } + + // is this a local? + if (localSymbol != null) + { + // Check for variable declaration errors. + // Use the binder that owns the scope for the local because this (the current) binder + // might own nested scope. + hasErrors |= localSymbol.ScopeBinder.ValidateDeclarationNameConflictsInScope(localSymbol, diagnostics); + + if (!isVar) + { + return new BoundLocal(designation, localSymbol, constantValueOpt: null, type: declType, hasErrors: hasErrors); + } + + return new DeconstructionVariablePendingInference(designation, localSymbol, receiverOpt: null); + } - return new BoundLocal(designation, localSymbol, constantValueOpt: null, type: declType, hasErrors: hasErrors); + // Is this a field? + SourceMemberFieldSymbolFromDesignation field = LookupDeclaredField(designation); + + if ((object)field == null) + { + // We should have the right binder in the chain, cannot continue otherwise. + throw ExceptionUtilities.Unreachable; + } + + BoundThisReference receiver = ThisReference(designation, this.ContainingType, hasErrors: false, + wasCompilerGenerated: true); + + if (!isVar) + { + TypeSymbol fieldType = field.GetFieldType(this.FieldsBeingBound); + return new BoundFieldAccess(designation, + receiver, + field, + constantValueOpt: null, + resultKind: LookupResultKind.Viable, + type: fieldType, + hasErrors: hasErrors); } - return new DeconstructionLocalPendingInference(designation, localSymbol); + return new DeconstructionVariablePendingInference(designation, field, receiver); } } } diff --git a/src/Compilers/CSharp/Portable/Binder/ExpressionVariableFinder.cs b/src/Compilers/CSharp/Portable/Binder/ExpressionVariableFinder.cs index 5d11581263b0527a20755668ad974486e7e9ca30..b3186841dcb7eb000e24afacb5faf1bf397413b3 100644 --- a/src/Compilers/CSharp/Portable/Binder/ExpressionVariableFinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/ExpressionVariableFinder.cs @@ -384,9 +384,11 @@ protected override Symbol MakePatternVariable(DeclarationPatternSyntax node, Syn { throw ExceptionUtilities.Unreachable; } + protected override Symbol MakeOutVariable(DeclarationExpressionSyntax node, BaseArgumentListSyntax argumentListSyntax, SyntaxNode nodeToBind) { - return SourceMemberFieldSymbolFromDesignation.Create(_containingType, node.VariableDesignation(), _modifiers, _containingFieldOpt, nodeToBind); + return SourceMemberFieldSymbolFromDesignation.Create(_containingType, node.VariableDesignation(), node.Type(), + _modifiers, _containingFieldOpt, nodeToBind); } #region pool diff --git a/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml b/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml index d2fe8259b7386d3f423f8de8372bf416cfda0bb0..dea39f4afa270aced9c6390e0e6b5a6b9f74eeb6 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml +++ b/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml @@ -1601,10 +1601,13 @@ - - + + - + + + + diff --git a/src/Compilers/CSharp/Portable/BoundTree/DeconstructionLocalPendingInference.cs b/src/Compilers/CSharp/Portable/BoundTree/DeconstructionLocalPendingInference.cs deleted file mode 100644 index 9efcd8fdf221200010ca591eeeb8db41331bf1b9..0000000000000000000000000000000000000000 --- a/src/Compilers/CSharp/Portable/BoundTree/DeconstructionLocalPendingInference.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using Microsoft.CodeAnalysis.CSharp.Symbols; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using System.Diagnostics; - -namespace Microsoft.CodeAnalysis.CSharp -{ - internal partial class DeconstructionLocalPendingInference - { - public BoundLocal SetInferredType(TypeSymbol type, bool success) - { - Debug.Assert((object)type != null); - Debug.Assert(this.Syntax.Kind() == SyntaxKind.SingleVariableDesignation); - - this.LocalSymbol.SetType(type); - return new BoundLocal(this.Syntax, this.LocalSymbol, constantValueOpt: null, type: type, hasErrors: this.HasErrors || !success); - } - - public BoundLocal FailInference(Binder binder) - { - return this.SetInferredType(binder.CreateErrorType("var"), success: false); - } - } -} \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/BoundTree/DeconstructionVariablePendingInference.cs b/src/Compilers/CSharp/Portable/BoundTree/DeconstructionVariablePendingInference.cs new file mode 100644 index 0000000000000000000000000000000000000000..5b8d27aa9321a024e979818eb83444d37327ce08 --- /dev/null +++ b/src/Compilers/CSharp/Portable/BoundTree/DeconstructionVariablePendingInference.cs @@ -0,0 +1,64 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Microsoft.CodeAnalysis.CSharp.Symbols; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System.Diagnostics; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.CSharp +{ + internal partial class DeconstructionVariablePendingInference + { + public BoundExpression SetInferredType(TypeSymbol type, Binder binderOpt, DiagnosticBag diagnostics) + { + Debug.Assert(binderOpt != null || (object)type != null); + Debug.Assert(this.Syntax.Kind() == SyntaxKind.SingleVariableDesignation); + + bool inferenceFailed = ((object)type == null); + + if (inferenceFailed) + { + type = binderOpt.CreateErrorType("var"); + } + + switch (this.VariableSymbol.Kind) + { + case SymbolKind.Local: + var local = (SourceLocalSymbol)this.VariableSymbol; + if (inferenceFailed) + { + ReportInferenceFailure(diagnostics); + } + local.SetType(type); + return new BoundLocal(this.Syntax, local, constantValueOpt: null, type: type, hasErrors: this.HasErrors || inferenceFailed); + + case SymbolKind.Field: + var field = (SourceMemberFieldSymbolFromDesignation)this.VariableSymbol; + var inferenceDiagnostics = DiagnosticBag.GetInstance(); + if (inferenceFailed) + { + ReportInferenceFailure(inferenceDiagnostics); + } + field.SetType(type, inferenceDiagnostics); + inferenceDiagnostics.Free(); + return new BoundFieldAccess(this.Syntax, this.ReceiverOpt, field, constantValueOpt: null, hasErrors: this.HasErrors || inferenceFailed); + + default: + throw ExceptionUtilities.Unreachable; + } + } + + private void ReportInferenceFailure(DiagnosticBag diagnostics) + { + var designation = (SingleVariableDesignationSyntax)this.Syntax; + Binder.Error( + diagnostics, ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable, designation.Identifier, + designation.Identifier.ValueText); + } + + public BoundExpression FailInference(Binder binder, DiagnosticBag diagnosticsOpt) + { + return this.SetInferredType(null, binder, diagnosticsOpt); + } + } +} \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/BoundTree/Expression.cs b/src/Compilers/CSharp/Portable/BoundTree/Expression.cs index 23c6d54566c5ce348542ad9d875f0fa63533dae7..e32517f69e79c1bf2bdc665adb761c106ce70af6 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/Expression.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/Expression.cs @@ -3000,7 +3000,7 @@ protected override OperationKind ExpressionKind /// This node represents a deconstruction local. /// It is only used temporarily during initial binding. /// - internal partial class DeconstructionLocalPendingInference + internal partial class DeconstructionVariablePendingInference { public override void Accept(OperationVisitor visitor) { diff --git a/src/Compilers/CSharp/Portable/BoundTree/Formatting.cs b/src/Compilers/CSharp/Portable/BoundTree/Formatting.cs index 4610eec32e0e4c4a74bd69018e911df0c7a2ebf2..13893179ecc29c7d49b81037b7c28b38e2a9c205 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/Formatting.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/Formatting.cs @@ -120,7 +120,7 @@ public override object Display } } - internal partial class DeconstructionLocalPendingInference + internal partial class DeconstructionVariablePendingInference { public override object Display { diff --git a/src/Compilers/CSharp/Portable/CSharpCodeAnalysis.csproj b/src/Compilers/CSharp/Portable/CSharpCodeAnalysis.csproj index e981f3fe6746372c22f7ffde2eba6ef3839bbbe8..808f5f1444d1a58c475254123039ad954b5565da 100644 --- a/src/Compilers/CSharp/Portable/CSharpCodeAnalysis.csproj +++ b/src/Compilers/CSharp/Portable/CSharpCodeAnalysis.csproj @@ -199,7 +199,7 @@ - + diff --git a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs index 169bd8db7e6af3ea93824d1f2b2418ca827e4798..7f93516114f6978e0cab0b8a41f1ddbddf24e806 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs +++ b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs @@ -3103,15 +3103,6 @@ internal class CSharpResources { } } - /// - /// Looks up a localized string similar to The type information on the left-hand-side '{0}' and right-hand-side '{1}' of the deconstruction was insufficient to infer a merged type.. - /// - internal static string ERR_DeconstructCouldNotInferMergedType { - get { - return ResourceManager.GetString("ERR_DeconstructCouldNotInferMergedType", resourceCulture); - } - } - /// /// Looks up a localized string similar to Deconstruction 'var (...)' form disallows a specific type for 'var'.. /// @@ -8881,6 +8872,15 @@ internal class CSharpResources { } } + /// + /// Looks up a localized string similar to Cannot infer the type of implicitly-typed deconstruction variable '{0}'.. + /// + internal static string ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable { + get { + return ResourceManager.GetString("ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable", resourceCulture); + } + } + /// /// Looks up a localized string similar to Cannot infer the type of implicitly-typed out variable '{0}'.. /// diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index da2a0deefea53fd869f6255aac84910249cbd4c0..9de9c2a3c46cbfa3acff483417685ff4951818dc 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -4908,6 +4908,9 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Cannot infer the type of implicitly-typed out variable '{0}'. + + Cannot infer the type of implicitly-typed deconstruction variable '{0}'. + Cannot deconstruct a tuple of '{0}' elements into '{1}' variables. @@ -4935,9 +4938,6 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Cannot reference 'System.Runtime.CompilerServices.TupleElementNamesAttribute' explicitly. Use the tuple syntax to define tuple names. - - The type information on the left-hand-side '{0}' and right-hand-side '{1}' of the deconstruction was insufficient to infer a merged type. - An expression tree may not contain an out argument variable declaration. diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs index a9cb6c083df55869d41ffad1287d6a575ee5bcaf..a15bfd0186ff1646fc5e1a117d122edc3033d3d1 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs @@ -1371,7 +1371,7 @@ internal enum ErrorCode ERR_TupleDuplicateMemberName = 8127, ERR_PredefinedTypeMemberNotFoundInAssembly = 8128, ERR_MissingDeconstruct = 8129, - ERR_DeconstructCouldNotInferMergedType = 8130, + ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable = 8130, ERR_DeconstructRequiresExpression = 8131, ERR_DeconstructWrongCardinality = 8132, ERR_CannotDeconstructDynamic = 8133, diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/PreciseAbstractFlowPass.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/PreciseAbstractFlowPass.cs index b5b68351c96f4938c467c05c625d69ce8d238fa9..b3b4b56801ef847e79059fdbf976996efd7f77b7 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/PreciseAbstractFlowPass.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/PreciseAbstractFlowPass.cs @@ -2654,7 +2654,7 @@ public override sealed BoundNode VisitOutVariablePendingInference(OutVariablePen throw ExceptionUtilities.Unreachable; } - public sealed override BoundNode VisitDeconstructionLocalPendingInference(DeconstructionLocalPendingInference node) + public sealed override BoundNode VisitDeconstructionVariablePendingInference(DeconstructionVariablePendingInference node) { throw ExceptionUtilities.Unreachable; } diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter.cs index 7224ff13eef13aa022ebc44a3f59f046d60e38b9..2b259cab086dcabe8e0fa8ac7c142617926d2540 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter.cs @@ -285,9 +285,9 @@ public override sealed BoundNode VisitOutDeconstructVarPendingInference(OutDecon throw ExceptionUtilities.Unreachable; } - public override BoundNode VisitDeconstructionLocalPendingInference(DeconstructionLocalPendingInference node) + public override BoundNode VisitDeconstructionVariablePendingInference(DeconstructionVariablePendingInference node) { - // DeconstructionLocalPendingInference nodes are only used within initial binding, but don't survive past that stage + // DeconstructionVariablePendingInference nodes are only used within initial binding, but don't survive past that stage throw ExceptionUtilities.Unreachable; } diff --git a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs index 18215d9995f0f16efd0bc497b49fefa4af0d22fd..ec52fd509ce032abeff55be9368608ad2e3577db 100644 --- a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs +++ b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs @@ -2406,6 +2406,17 @@ private MemberDeclarationSyntax ParseMemberDeclarationOrStatement(SyntaxKind par } } + if (acceptStatement) + { + var deconstruction = ParseDeconstructionDeclarationAssignment(); + if (deconstruction != null) + { + var semicolon = this.EatToken(SyntaxKind.SemicolonToken); + return _syntaxFactory.GlobalStatement(_syntaxFactory.DeconstructionDeclarationStatement( + new SyntaxList(), deconstruction, semicolon)); + } + } + // Everything that's left -- methods, fields, properties, // indexers, and non-conversion operators -- starts with a type // (possibly void). Parse that. diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs index cb046a6d415f689fad2e91e49aad63110a180259..d6b54cb98dfb82b6706ea840a3460f3bbbb45e44 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs @@ -2892,7 +2892,7 @@ private static bool HasNonConstantInitializer(ArrayBuilder builder, VariableComponentSyntax variableComponent, + VariableComponentAssignmentSyntax assignment) + { + switch (variableComponent.Kind()) + { + case SyntaxKind.TypedVariableComponent: + var typed = (TypedVariableComponentSyntax)variableComponent; + CollectFieldsFromGlobalDeconstruction( + builder, + typed.Designation, + typed.Type, + assignment); + break; + + case SyntaxKind.ParenthesizedVariableComponent: + foreach (VariableComponentSyntax variable in ((ParenthesizedVariableComponentSyntax)variableComponent).Variables) + { + CollectFieldsFromGlobalDeconstruction(builder, variable, assignment); + } + break; + + default: + throw ExceptionUtilities.UnexpectedValue(variableComponent.Kind()); + } + } + + private void CollectFieldsFromGlobalDeconstruction(ArrayBuilder builder, VariableDesignationSyntax designation, + TypeSyntax type, VariableComponentAssignmentSyntax assignment) + { + switch (designation.Kind()) + { + case SyntaxKind.SingleVariableDesignation: + var field = SourceMemberFieldSymbolFromDesignation.Create(this, (SingleVariableDesignationSyntax)designation, + type, DeclarationModifiers.Private, null, assignment); + + builder.Add(field); + + break; + + case SyntaxKind.ParenthesizedVariableDesignation: + foreach (VariableDesignationSyntax variable in ((ParenthesizedVariableDesignationSyntax)designation).Variables) + { + CollectFieldsFromGlobalDeconstruction(builder, variable, type, assignment); + } + break; + + default: + throw ExceptionUtilities.UnexpectedValue(designation.Kind()); + } + } + private static bool IsGlobalCodeAllowed(CSharpSyntaxNode parent) { var parentKind = parent.Kind(); diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbolFromDesignation.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbolFromDesignation.cs index 92353efd3ec70da7b49d6f4c4fb8c3c53cdb5135..e33de8b313764b6c19131d7d0dbdd902e9a47cbf 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbolFromDesignation.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbolFromDesignation.cs @@ -15,28 +15,34 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols internal class SourceMemberFieldSymbolFromDesignation : SourceMemberFieldSymbol { private TypeSymbol _lazyType; + private SyntaxReference _typeSyntax; internal SourceMemberFieldSymbolFromDesignation( SourceMemberContainerTypeSymbol containingType, SingleVariableDesignationSyntax designation, + TypeSyntax typeSyntax, DeclarationModifiers modifiers) : base(containingType, modifiers, designation.Identifier.ValueText, designation.GetReference(), designation.Identifier.GetLocation()) { Debug.Assert(DeclaredAccessibility == Accessibility.Private); + _typeSyntax = typeSyntax.GetReference(); } internal static SourceMemberFieldSymbolFromDesignation Create( SourceMemberContainerTypeSymbol containingType, SingleVariableDesignationSyntax designation, + TypeSyntax typeSyntax, DeclarationModifiers modifiers, FieldSymbol containingFieldOpt, SyntaxNode nodeToBind) { - Debug.Assert(nodeToBind.Kind() == SyntaxKind.VariableDeclarator || nodeToBind is ExpressionSyntax); - var typeSyntax = ((TypedVariableComponentSyntax)designation.Parent).Type; + Debug.Assert(nodeToBind.Kind() == SyntaxKind.VariableDeclarator + || nodeToBind is ExpressionSyntax + || nodeToBind.Kind() == SyntaxKind.VariableComponentAssignment); + return typeSyntax.IsVar - ? new SourceMemberFieldSymbolFromDesignationWithEnclosingContext(containingType, designation, modifiers, containingFieldOpt, nodeToBind) - : new SourceMemberFieldSymbolFromDesignation(containingType, designation, modifiers); + ? new SourceMemberFieldSymbolFromDesignationWithEnclosingContext(containingType, designation, typeSyntax, modifiers, containingFieldOpt, nodeToBind) + : new SourceMemberFieldSymbolFromDesignation(containingType, designation, typeSyntax, modifiers); } protected override SyntaxList AttributeDeclarationSyntaxList @@ -54,14 +60,8 @@ public SingleVariableDesignationSyntax VariableDesignation return (SingleVariableDesignationSyntax)this.SyntaxNode; } } - - protected override TypeSyntax TypeSyntax - { - get - { - return ((TypedVariableComponentSyntax)VariableDesignation.Parent).Type; - } - } + + protected override TypeSyntax TypeSyntax => (TypeSyntax)_typeSyntax.GetSyntax(); protected override SyntaxTokenList ModifiersTokenList { @@ -170,16 +170,19 @@ private class SourceMemberFieldSymbolFromDesignationWithEnclosingContext : Sourc private readonly FieldSymbol _containingFieldOpt; private readonly SyntaxReference _nodeToBind; - internal SourceMemberFieldSymbolFromDesignationWithEnclosingContext( SourceMemberContainerTypeSymbol containingType, SingleVariableDesignationSyntax designation, + TypeSyntax typeSyntax, DeclarationModifiers modifiers, FieldSymbol containingFieldOpt, SyntaxNode nodeToBind) - : base(containingType, designation, modifiers) + : base(containingType, designation, typeSyntax, modifiers) { - Debug.Assert(nodeToBind.Kind() == SyntaxKind.VariableDeclarator || nodeToBind is ExpressionSyntax); + Debug.Assert(nodeToBind.Kind() == SyntaxKind.VariableDeclarator + || nodeToBind is ExpressionSyntax + || nodeToBind.Kind() == SyntaxKind.VariableComponentAssignment); + _containingFieldOpt = containingFieldOpt; _nodeToBind = nodeToBind.GetReference(); } @@ -207,6 +210,14 @@ protected override void InferFieldType(ConsList fieldsBeingBound, B binder.BindDeclaratorArguments((VariableDeclaratorSyntax)nodeToBind, diagnostics); break; + case SyntaxKind.VariableComponentAssignment: + var deconstruction = (VariableComponentAssignmentSyntax)nodeToBind; + + binder.BindDeconstructionDeclaration(deconstruction, deconstruction.VariableComponent, + deconstruction.Value, diagnostics); + + break; + default: binder.BindExpression((ExpressionSyntax)nodeToBind, diagnostics); break; diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenDeconstructTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenDeconstructTests.cs index 6d90d4bb1a70009c73978f26c875041fda5cd473..5b56ce1d33237e0772cde9fefe36b227b073a2d4 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenDeconstructTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenDeconstructTests.cs @@ -1968,15 +1968,15 @@ static void Main() var tree = compilation.SyntaxTrees.First(); var model = compilation.GetSemanticModel(tree); - var x1 = GetDeconstructionLocal(tree, "x1"); + var x1 = GetDeconstructionVariable(tree, "x1"); var x1Ref = GetReference(tree, "x1"); VerifyModelForDeconstructionLocal(model, x1, x1Ref); - var x2 = GetDeconstructionLocal(tree, "x2"); + var x2 = GetDeconstructionVariable(tree, "x2"); var x2Ref = GetReference(tree, "x2"); VerifyModelForDeconstructionLocal(model, x2, x2Ref); - var x3 = GetDeconstructionLocal(tree, "x3"); + var x3 = GetDeconstructionVariable(tree, "x3"); var x3Ref = GetReference(tree, "x3"); VerifyModelForDeconstructionLocal(model, x3, x3Ref); }; @@ -2006,15 +2006,15 @@ static void Main() var tree = compilation.SyntaxTrees.First(); var model = compilation.GetSemanticModel(tree); - var x1 = GetDeconstructionLocal(tree, "x1"); + var x1 = GetDeconstructionVariable(tree, "x1"); var x1Ref = GetReference(tree, "x1"); VerifyModelForDeconstructionLocal(model, x1, x1Ref); - var x2 = GetDeconstructionLocal(tree, "x2"); + var x2 = GetDeconstructionVariable(tree, "x2"); var x2Ref = GetReference(tree, "x2"); VerifyModelForDeconstructionLocal(model, x2, x2Ref); - var x3 = GetDeconstructionLocal(tree, "x3"); + var x3 = GetDeconstructionVariable(tree, "x3"); var x3Ref = GetReference(tree, "x3"); VerifyModelForDeconstructionLocal(model, x3, x3Ref); }; @@ -2173,15 +2173,15 @@ static void Main() var tree = compilation.SyntaxTrees.First(); var model = compilation.GetSemanticModel(tree); - var x1 = GetDeconstructionLocal(tree, "x1"); + var x1 = GetDeconstructionVariable(tree, "x1"); var x1Ref = GetReference(tree, "x1"); VerifyModelForDeconstructionLocal(model, x1, x1Ref); - var x2 = GetDeconstructionLocal(tree, "x2"); + var x2 = GetDeconstructionVariable(tree, "x2"); var x2Ref = GetReference(tree, "x2"); VerifyModelForDeconstructionLocal(model, x2, x2Ref); - var x3 = GetDeconstructionLocal(tree, "x3"); + var x3 = GetDeconstructionVariable(tree, "x3"); var x3Ref = GetReference(tree, "x3"); VerifyModelForDeconstructionLocal(model, x3, x3Ref); }; @@ -2237,12 +2237,31 @@ private static void VerifyModelForDeconstruction(SemanticModel model, SingleVari } } + private static void VerifyModelForDeconstructionField(SemanticModel model, SingleVariableDesignationSyntax decl, params IdentifierNameSyntax[] references) + { + var field = (FieldSymbol)model.GetDeclaredSymbol(decl); + Assert.Equal(decl.Identifier.ValueText, field.Name); + Assert.Equal(SymbolKind.Field, ((FieldSymbol)field).Kind); + Assert.Same(field, model.GetDeclaredSymbol((SyntaxNode)decl)); + Assert.Same(field, model.LookupSymbols(decl.SpanStart, name: decl.Identifier.ValueText).Single()); + Assert.Equal(Accessibility.Private, field.DeclaredAccessibility); + Assert.True(model.LookupNames(decl.SpanStart).Contains(decl.Identifier.ValueText)); + + foreach (var reference in references) + { + Assert.Same(field, model.GetSymbolInfo(reference).Symbol); + Assert.Same(field, model.LookupSymbols(reference.SpanStart, name: decl.Identifier.ValueText).Single()); + Assert.True(model.LookupNames(reference.SpanStart).Contains(decl.Identifier.ValueText)); + Assert.Equal(field.Type, model.GetTypeInfo(reference).Type); + } + } + private static TypeSyntax GetTypeSyntax(SingleVariableDesignationSyntax decl) { return (decl.Parent as TypedVariableComponentSyntax)?.Type; } - private static SingleVariableDesignationSyntax GetDeconstructionLocal(SyntaxTree tree, string name) + private static SingleVariableDesignationSyntax GetDeconstructionVariable(SyntaxTree tree, string name) { return tree.GetRoot().DescendantNodes().OfType().Where(d => d.Identifier.ValueText == name).Single(); } @@ -2289,11 +2308,11 @@ class var var tree = compilation.SyntaxTrees.First(); var model = compilation.GetSemanticModel(tree); - var x1 = GetDeconstructionLocal(tree, "x1"); + var x1 = GetDeconstructionVariable(tree, "x1"); var x1Ref = GetReference(tree, "x1"); VerifyModelForDeconstructionLocal(model, x1, x1Ref); - var x2 = GetDeconstructionLocal(tree, "x2"); + var x2 = GetDeconstructionVariable(tree, "x2"); var x2Ref = GetReference(tree, "x2"); VerifyModelForDeconstructionLocal(model, x2, x2Ref); @@ -2334,19 +2353,19 @@ static void Main() var tree = compilation.SyntaxTrees.First(); var model = compilation.GetSemanticModel(tree); - var x1 = GetDeconstructionLocal(tree, "x1"); + var x1 = GetDeconstructionVariable(tree, "x1"); var x1Ref = GetReference(tree, "x1"); VerifyModelForDeconstructionLocal(model, x1, x1Ref); - var x2 = GetDeconstructionLocal(tree, "x2"); + var x2 = GetDeconstructionVariable(tree, "x2"); var x2Ref = GetReference(tree, "x2"); VerifyModelForDeconstructionLocal(model, x2, x2Ref); - var x3 = GetDeconstructionLocal(tree, "x3"); + var x3 = GetDeconstructionVariable(tree, "x3"); var x3Ref = GetReference(tree, "x3"); VerifyModelForDeconstructionLocal(model, x3, x3Ref); - var x4 = GetDeconstructionLocal(tree, "x4"); + var x4 = GetDeconstructionVariable(tree, "x4"); var x4Ref = GetReference(tree, "x4"); VerifyModelForDeconstructionLocal(model, x4, x4Ref); @@ -2391,11 +2410,11 @@ class D var tree = compilation.SyntaxTrees.First(); var model = compilation.GetSemanticModel(tree); - var x1 = GetDeconstructionLocal(tree, "x1"); + var x1 = GetDeconstructionVariable(tree, "x1"); var x1Ref = GetReference(tree, "x1"); VerifyModelForDeconstructionLocal(model, x1, x1Ref); - var x2 = GetDeconstructionLocal(tree, "x2"); + var x2 = GetDeconstructionVariable(tree, "x2"); var x2Ref = GetReference(tree, "x2"); VerifyModelForDeconstructionLocal(model, x2, x2Ref); @@ -2441,11 +2460,11 @@ static void Main() var tree = compilation.SyntaxTrees.First(); var model = compilation.GetSemanticModel(tree); - var x1 = GetDeconstructionLocal(tree, "x1"); + var x1 = GetDeconstructionVariable(tree, "x1"); var x1Ref = GetReferences(tree, "x1", 4); VerifyModelForDeconstructionFor(model, x1, x1Ref); - var x2 = GetDeconstructionLocal(tree, "x2"); + var x2 = GetDeconstructionVariable(tree, "x2"); var x2Ref = GetReferences(tree, "x2", 3); VerifyModelForDeconstructionFor(model, x2, x2Ref); @@ -2486,11 +2505,11 @@ class var var tree = compilation.SyntaxTrees.First(); var model = compilation.GetSemanticModel(tree); - var x1 = GetDeconstructionLocal(tree, "x1"); + var x1 = GetDeconstructionVariable(tree, "x1"); var x1Ref = GetReferences(tree, "x1", 3); VerifyModelForDeconstructionFor(model, x1, x1Ref); - var x2 = GetDeconstructionLocal(tree, "x2"); + var x2 = GetDeconstructionVariable(tree, "x2"); var x2Ref = GetReference(tree, "x2"); VerifyModelForDeconstructionFor(model, x2, x2Ref); @@ -2532,11 +2551,11 @@ static void Main() var tree = compilation.SyntaxTrees.First(); var model = compilation.GetSemanticModel(tree); - var x1 = GetDeconstructionLocal(tree, "x1"); + var x1 = GetDeconstructionVariable(tree, "x1"); var x1Ref = GetReferences(tree, "x1", 3); VerifyModelForDeconstructionFor(model, x1, x1Ref); - var x2 = GetDeconstructionLocal(tree, "x2"); + var x2 = GetDeconstructionVariable(tree, "x2"); var x2Ref = GetReference(tree, "x2"); VerifyModelForDeconstructionFor(model, x2, x2Ref); @@ -2581,11 +2600,11 @@ static void Main() var tree = compilation.SyntaxTrees.First(); var model = compilation.GetSemanticModel(tree); - var x1 = GetDeconstructionLocal(tree, "x1"); + var x1 = GetDeconstructionVariable(tree, "x1"); var x1Ref = GetReference(tree, "x1"); VerifyModelForDeconstructionForeach(model, x1, x1Ref); - var x2 = GetDeconstructionLocal(tree, "x2"); + var x2 = GetDeconstructionVariable(tree, "x2"); var x2Ref = GetReference(tree, "x2"); VerifyModelForDeconstructionForeach(model, x2, x2Ref); @@ -2668,13 +2687,13 @@ static void Main() var tree = compilation.SyntaxTrees.First(); var model = compilation.GetSemanticModel(tree); - var x1 = GetDeconstructionLocal(tree, "x1"); + var x1 = GetDeconstructionVariable(tree, "x1"); var x1Ref = GetReference(tree, "x1"); var symbol = model.GetDeclaredSymbol(x1); VerifyModelForDeconstructionForeach(model, x1, x1Ref); - var x2 = GetDeconstructionLocal(tree, "x2"); + var x2 = GetDeconstructionVariable(tree, "x2"); var x2Ref = GetReference(tree, "x2"); VerifyModelForDeconstructionForeach(model, x2, x2Ref); @@ -2770,11 +2789,11 @@ static void Main() var tree = compilation.SyntaxTrees.First(); var model = compilation.GetSemanticModel(tree); - var x1 = GetDeconstructionLocal(tree, "x1"); + var x1 = GetDeconstructionVariable(tree, "x1"); var x1Ref = GetReference(tree, "x1"); VerifyModelForDeconstructionForeach(model, x1, x1Ref); - var x2 = GetDeconstructionLocal(tree, "x2"); + var x2 = GetDeconstructionVariable(tree, "x2"); var x2Ref = GetReference(tree, "x2"); VerifyModelForDeconstructionForeach(model, x2, x2Ref); @@ -2884,11 +2903,11 @@ public static void Deconstruct(this char value, out int item1, out int item2) var tree = compilation.SyntaxTrees.First(); var model = compilation.GetSemanticModel(tree); - var x1 = GetDeconstructionLocal(tree, "x1"); + var x1 = GetDeconstructionVariable(tree, "x1"); var x1Ref = GetReference(tree, "x1"); VerifyModelForDeconstructionForeach(model, x1, x1Ref); - var x2 = GetDeconstructionLocal(tree, "x2"); + var x2 = GetDeconstructionVariable(tree, "x2"); var x2Ref = GetReference(tree, "x2"); VerifyModelForDeconstructionForeach(model, x2, x2Ref); @@ -2967,23 +2986,23 @@ static void Main() var tree = compilation.SyntaxTrees.First(); var model = compilation.GetSemanticModel(tree); - var x1 = GetDeconstructionLocal(tree, "x1"); + var x1 = GetDeconstructionVariable(tree, "x1"); var x1Ref = GetReference(tree, "x1"); VerifyModelForDeconstructionForeach(model, x1, x1Ref); - var x2 = GetDeconstructionLocal(tree, "x2"); + var x2 = GetDeconstructionVariable(tree, "x2"); var x2Ref = GetReference(tree, "x2"); VerifyModelForDeconstructionForeach(model, x2, x2Ref); - var x3 = GetDeconstructionLocal(tree, "x3"); + var x3 = GetDeconstructionVariable(tree, "x3"); var x3Ref = GetReference(tree, "x3"); VerifyModelForDeconstructionForeach(model, x3, x3Ref); - var x4 = GetDeconstructionLocal(tree, "x4"); + var x4 = GetDeconstructionVariable(tree, "x4"); var x4Ref = GetReference(tree, "x4"); VerifyModelForDeconstructionForeach(model, x4, x4Ref); - var x5 = GetDeconstructionLocal(tree, "x5"); + var x5 = GetDeconstructionVariable(tree, "x5"); var x5Ref = GetReference(tree, "x5"); VerifyModelForDeconstructionForeach(model, x5, x5Ref); @@ -3094,15 +3113,15 @@ static void Main() var tree = compilation.SyntaxTrees.First(); var model = compilation.GetSemanticModel(tree); - var x1 = GetDeconstructionLocal(tree, "x1"); + var x1 = GetDeconstructionVariable(tree, "x1"); var x1Ref = GetReference(tree, "x1"); VerifyModelForDeconstructionForeach(model, x1, x1Ref); - var x2 = GetDeconstructionLocal(tree, "x2"); + var x2 = GetDeconstructionVariable(tree, "x2"); var x2Ref = GetReference(tree, "x2"); VerifyModelForDeconstructionForeach(model, x2, x2Ref); - var x3 = GetDeconstructionLocal(tree, "x3"); + var x3 = GetDeconstructionVariable(tree, "x3"); var x3Ref = GetReference(tree, "x3"); VerifyModelForDeconstructionForeach(model, x3, x3Ref); @@ -3436,5 +3455,954 @@ public void Deconstruct(out int a, out int b) var comp = CompileAndVerify(source, expectedOutput: "3 4", additionalRefs: new[] { ValueTupleRef, SystemRuntimeFacadeRef, CSharpRef, SystemCoreRef }); comp.VerifyDiagnostics(); } + + [Fact] + public void FieldAndLocalWithSameName() + { + string source = @" +class C +{ + public int x = 3; + static void Main() + { + new C().M(); + } + void M() + { + var (x, y) = (1, 2); + System.Console.Write($""{x} {y} {this.x}""); + } +} +"; + var comp = CompileAndVerify(source, expectedOutput: "1 2 3", additionalRefs: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); + comp.VerifyDiagnostics(); + } + + [Fact] + public void NoGlobalDeconstructionUnlessScript() + { + string source = @" +class C +{ + var (x, y) = (1, 2); +} +"; + var comp = CreateCompilationWithMscorlib(source, references: s_valueTupleRefs); + comp.VerifyDiagnostics( + // (3,2): error CS1520: Method must have a return type + // { + Diagnostic(ErrorCode.ERR_MemberNeedsType, "").WithLocation(3, 2), + // (4,11): error CS1001: Identifier expected + // var (x, y) = (1, 2); + Diagnostic(ErrorCode.ERR_IdentifierExpected, ",").WithLocation(4, 11), + // (4,14): error CS1001: Identifier expected + // var (x, y) = (1, 2); + Diagnostic(ErrorCode.ERR_IdentifierExpected, ")").WithLocation(4, 14), + // (4,16): error CS1002: ; expected + // var (x, y) = (1, 2); + Diagnostic(ErrorCode.ERR_SemicolonExpected, "=").WithLocation(4, 16), + // (4,16): error CS1519: Invalid token '=' in class, struct, or interface member declaration + // var (x, y) = (1, 2); + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "=").WithArguments("=").WithLocation(4, 16), + // (4,18): error CS8124: Tuple must contain at least two elements. + // var (x, y) = (1, 2); + Diagnostic(ErrorCode.ERR_TupleTooFewElements, "(").WithLocation(4, 18), + // (4,19): error CS1031: Type expected + // var (x, y) = (1, 2); + Diagnostic(ErrorCode.ERR_TypeExpected, "1").WithLocation(4, 19), + // (4,19): error CS1026: ) expected + // var (x, y) = (1, 2); + Diagnostic(ErrorCode.ERR_CloseParenExpected, "1").WithLocation(4, 19), + // (4,19): error CS1519: Invalid token '1' in class, struct, or interface member declaration + // var (x, y) = (1, 2); + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "1").WithArguments("1").WithLocation(4, 19), + // (4,10): error CS0246: The type or namespace name 'x' could not be found (are you missing a using directive or an assembly reference?) + // var (x, y) = (1, 2); + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "x").WithArguments("x").WithLocation(4, 10), + // (4,13): error CS0246: The type or namespace name 'y' could not be found (are you missing a using directive or an assembly reference?) + // var (x, y) = (1, 2); + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "y").WithArguments("y").WithLocation(4, 13), + // (4,5): error CS0501: 'C.var(x, y)' must declare a body because it is not marked abstract, extern, or partial + // var (x, y) = (1, 2); + Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "var").WithArguments("C.var(x, y)").WithLocation(4, 5) + ); + + var nodes = comp.SyntaxTrees[0].GetCompilationUnitRoot().DescendantNodesAndSelf(); + Assert.False(nodes.Any(n => n.Kind() == SyntaxKind.DeconstructionDeclarationStatement)); + } + + [Fact] + public void SimpleDeconstructionInScript() + { + var source = +@" +using alias = System.Int32; +(string x, alias y) = (""hello"", 42); +System.Console.Write($""{x} {y}""); +"; + + Action validator = (ModuleSymbol module) => + { + var sourceModule = (SourceModuleSymbol)module; + var compilation = sourceModule.DeclaringCompilation; + var tree = compilation.SyntaxTrees.First(); + var model = compilation.GetSemanticModel(tree); + + var x = GetDeconstructionVariable(tree, "x"); + var xSymbol = model.GetDeclaredSymbol(x); + var xRef = GetReference(tree, "x"); + Assert.Equal("System.String Script.x", xSymbol.ToTestDisplayString()); + VerifyModelForDeconstructionField(model, x, xRef); + + var y = GetDeconstructionVariable(tree, "y"); + var ySymbol = model.GetDeclaredSymbol(y); + var yRef = GetReference(tree, "y"); + Assert.Equal("System.Int32 Script.y", ySymbol.ToTestDisplayString()); + VerifyModelForDeconstructionField(model, y, yRef); + + // extra checks on x + var xType = GetTypeSyntax(x); + Assert.Equal(SymbolKind.NamedType, model.GetSymbolInfo(xType).Symbol.Kind); + Assert.Equal("string", model.GetSymbolInfo(xType).Symbol.ToDisplayString()); + Assert.Null(model.GetAliasInfo(xType)); + + // extra checks on y + var yType = GetTypeSyntax(y); + Assert.Equal(SymbolKind.NamedType, model.GetSymbolInfo(yType).Symbol.Kind); + Assert.Equal("int", model.GetSymbolInfo(yType).Symbol.ToDisplayString()); + Assert.Equal("alias=System.Int32", model.GetAliasInfo(yType).ToTestDisplayString()); + }; + + var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); + + comp.VerifyDiagnostics(); + var verifier = CompileAndVerify(comp, expectedOutput: "hello 42", sourceSymbolValidator: validator); + verifier.VerifyIL("<>d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext()", @" +{ + // Code size 151 (0x97) + .maxstack 3 + .locals init (int V_0, + object V_1, + string V_2, + int V_3, + System.Exception V_4) + IL_0000: ldarg.0 + IL_0001: ldfld ""int <>d__0.<>1__state"" + IL_0006: stloc.0 + .try + { + IL_0007: ldstr ""hello"" + IL_000c: ldc.i4.s 42 + IL_000e: newobj ""System.ValueTuple..ctor(string, int)"" + IL_0013: dup + IL_0014: ldfld ""string System.ValueTuple.Item1"" + IL_0019: stloc.2 + IL_001a: ldfld ""int System.ValueTuple.Item2"" + IL_001f: stloc.3 + IL_0020: ldarg.0 + IL_0021: ldfld ""Script <>d__0.<>4__this"" + IL_0026: ldloc.2 + IL_0027: stfld ""string x"" + IL_002c: ldarg.0 + IL_002d: ldfld ""Script <>d__0.<>4__this"" + IL_0032: ldloc.3 + IL_0033: stfld ""int y"" + IL_0038: ldstr ""{0} {1}"" + IL_003d: ldarg.0 + IL_003e: ldfld ""Script <>d__0.<>4__this"" + IL_0043: ldfld ""string x"" + IL_0048: ldarg.0 + IL_0049: ldfld ""Script <>d__0.<>4__this"" + IL_004e: ldfld ""int y"" + IL_0053: box ""int"" + IL_0058: call ""string string.Format(string, object, object)"" + IL_005d: call ""void System.Console.Write(string)"" + IL_0062: nop + IL_0063: ldnull + IL_0064: stloc.1 + IL_0065: leave.s IL_0081 + } + catch System.Exception + { + IL_0067: stloc.s V_4 + IL_0069: ldarg.0 + IL_006a: ldc.i4.s -2 + IL_006c: stfld ""int <>d__0.<>1__state"" + IL_0071: ldarg.0 + IL_0072: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder <>d__0.<>t__builder"" + IL_0077: ldloc.s V_4 + IL_0079: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" + IL_007e: nop + IL_007f: leave.s IL_0096 + } + IL_0081: ldarg.0 + IL_0082: ldc.i4.s -2 + IL_0084: stfld ""int <>d__0.<>1__state"" + IL_0089: ldarg.0 + IL_008a: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder <>d__0.<>t__builder"" + IL_008f: ldloc.1 + IL_0090: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult(object)"" + IL_0095: nop + IL_0096: ret +}"); + } + + [Fact] + public void NoGlobalDeconstructionOutsideScript() + { + var source = +@" +(string x, int y) = (""hello"", 42); +"; + var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Regular, options: TestOptions.DebugExe, references: s_valueTupleRefs); + + comp.VerifyDiagnostics( + // (2,19): error CS1022: Type or namespace definition, or end-of-file expected + // (string x, int y) = ("hello", 42); + Diagnostic(ErrorCode.ERR_EOFExpected, "=").WithLocation(2, 19), + // (2,22): error CS1022: Type or namespace definition, or end-of-file expected + // (string x, int y) = ("hello", 42); + Diagnostic(ErrorCode.ERR_EOFExpected, @"""hello""").WithLocation(2, 22), + // (2,22): error CS1026: ) expected + // (string x, int y) = ("hello", 42); + Diagnostic(ErrorCode.ERR_CloseParenExpected, @"""hello""").WithLocation(2, 22), + // error CS5001: Program does not contain a static 'Main' method suitable for an entry point + Diagnostic(ErrorCode.ERR_NoEntryPoint).WithLocation(1, 1) + ); + + var nodes = comp.SyntaxTrees[0].GetCompilationUnitRoot().DescendantNodesAndSelf(); + Assert.False(nodes.Any(n => n.Kind() == SyntaxKind.DeconstructionDeclarationStatement)); + } + + [Fact] + public void NestedDeconstructionInScript() + { + var source = +@" +(string x, (int y, int z)) = (""hello"", (42, 43)); +System.Console.Write($""{x} {y} {z}""); +"; + var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); + + comp.VerifyDiagnostics(); + var verifier = CompileAndVerify(comp, expectedOutput: "hello 42 43"); + } + + [Fact] + public void VarDeconstructionInScript() + { + var source = +@" +(var x, var y) = (""hello"", 42); +System.Console.Write($""{x} {y}""); +"; + var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); + + comp.VerifyDiagnostics(); + var verifier = CompileAndVerify(comp, expectedOutput: "hello 42"); + } + + [Fact] + public void NestedVarDeconstructionInScript() + { + var source = +@" +(var x1, var (x2, x3)) = (""hello"", (42, 43)); +System.Console.Write($""{x1} {x2} {x3}""); +"; + + Action validator = (ModuleSymbol module) => + { + var sourceModule = (SourceModuleSymbol)module; + var compilation = sourceModule.DeclaringCompilation; + var tree = compilation.SyntaxTrees.First(); + var model = compilation.GetSemanticModel(tree); + + var x1 = GetDeconstructionVariable(tree, "x1"); + var x1Symbol = model.GetDeclaredSymbol(x1); + var x1Ref = GetReference(tree, "x1"); + Assert.Equal("System.String Script.x1", x1Symbol.ToTestDisplayString()); + VerifyModelForDeconstructionField(model, x1, x1Ref); + + var x2 = GetDeconstructionVariable(tree, "x2"); + var x2Symbol = model.GetDeclaredSymbol(x2); + var x2Ref = GetReference(tree, "x2"); + Assert.Equal("System.Int32 Script.x2", x2Symbol.ToTestDisplayString()); + VerifyModelForDeconstructionField(model, x2, x2Ref); + + // extra checks on x1's var + var x1Type = GetTypeSyntax(x1); + Assert.Equal(SymbolKind.NamedType, model.GetSymbolInfo(x1Type).Symbol.Kind); + Assert.Equal("string", model.GetSymbolInfo(x1Type).Symbol.ToDisplayString()); + Assert.Null(model.GetAliasInfo(x1Type)); + + // extra check on x2 and x3's var + var x23Var = (TypedVariableComponentSyntax)x2.Parent.Parent; + Assert.Equal("var", x23Var.Type.ToString()); + Assert.Null(model.GetSymbolInfo(x23Var.Type).Symbol); // The var in `var (x2, x3)` has no symbol + }; + + var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); + + comp.VerifyDiagnostics(); + var verifier = CompileAndVerify(comp, expectedOutput: "hello 42 43", sourceSymbolValidator: validator); + } + + [Fact] + public void EvaluationOrderForDeconstructionInScript() + { + var source = + @" +(int, int) M(out int x) { x = 1; return (2, 3); } +var (x2, x3) = M(out var x1); +System.Console.Write($""{x1} {x2} {x3}""); +"; + var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); + + comp.VerifyDiagnostics(); + var verifier = CompileAndVerify(comp, expectedOutput: "1 2 3"); + verifier.VerifyIL("<>d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext()", @" +{ + // Code size 182 (0xb6) + .maxstack 4 + .locals init (int V_0, + object V_1, + int V_2, + int V_3, + System.Exception V_4) + IL_0000: ldarg.0 + IL_0001: ldfld ""int <>d__0.<>1__state"" + IL_0006: stloc.0 + .try + { + IL_0007: ldarg.0 + IL_0008: ldfld ""Script <>d__0.<>4__this"" + IL_000d: ldarg.0 + IL_000e: ldfld ""Script <>d__0.<>4__this"" + IL_0013: ldflda ""int x1"" + IL_0018: callvirt ""(int, int) M(out int)"" + IL_001d: dup + IL_001e: ldfld ""int System.ValueTuple.Item1"" + IL_0023: stloc.2 + IL_0024: ldfld ""int System.ValueTuple.Item2"" + IL_0029: stloc.3 + IL_002a: ldarg.0 + IL_002b: ldfld ""Script <>d__0.<>4__this"" + IL_0030: ldloc.2 + IL_0031: stfld ""int x2"" + IL_0036: ldarg.0 + IL_0037: ldfld ""Script <>d__0.<>4__this"" + IL_003c: ldloc.3 + IL_003d: stfld ""int x3"" + IL_0042: ldstr ""{0} {1} {2}"" + IL_0047: ldarg.0 + IL_0048: ldfld ""Script <>d__0.<>4__this"" + IL_004d: ldfld ""int x1"" + IL_0052: box ""int"" + IL_0057: ldarg.0 + IL_0058: ldfld ""Script <>d__0.<>4__this"" + IL_005d: ldfld ""int x2"" + IL_0062: box ""int"" + IL_0067: ldarg.0 + IL_0068: ldfld ""Script <>d__0.<>4__this"" + IL_006d: ldfld ""int x3"" + IL_0072: box ""int"" + IL_0077: call ""string string.Format(string, object, object, object)"" + IL_007c: call ""void System.Console.Write(string)"" + IL_0081: nop + IL_0082: ldnull + IL_0083: stloc.1 + IL_0084: leave.s IL_00a0 + } + catch System.Exception + { + IL_0086: stloc.s V_4 + IL_0088: ldarg.0 + IL_0089: ldc.i4.s -2 + IL_008b: stfld ""int <>d__0.<>1__state"" + IL_0090: ldarg.0 + IL_0091: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder <>d__0.<>t__builder"" + IL_0096: ldloc.s V_4 + IL_0098: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" + IL_009d: nop + IL_009e: leave.s IL_00b5 + } + IL_00a0: ldarg.0 + IL_00a1: ldc.i4.s -2 + IL_00a3: stfld ""int <>d__0.<>1__state"" + IL_00a8: ldarg.0 + IL_00a9: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder <>d__0.<>t__builder"" + IL_00ae: ldloc.1 + IL_00af: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult(object)"" + IL_00b4: nop + IL_00b5: ret +} +"); + } + + [Fact] + public void DeconstructionForEachInScript() + { + var source = +@" +foreach ((string x1, var (x2, x3)) in new[] { (""hello"", (42, ""world"")) }) +{ + System.Console.Write($""{x1} {x2} {x3}""); +} +"; + + Action validator = (ModuleSymbol module) => + { + var sourceModule = (SourceModuleSymbol)module; + var compilation = sourceModule.DeclaringCompilation; + var tree = compilation.SyntaxTrees.First(); + var model = compilation.GetSemanticModel(tree); + + var x1 = GetDeconstructionVariable(tree, "x1"); + var x1Symbol = model.GetDeclaredSymbol(x1); + Assert.Equal("System.String x1", x1Symbol.ToTestDisplayString()); + Assert.Equal(SymbolKind.Local, x1Symbol.Kind); + + var x2 = GetDeconstructionVariable(tree, "x2"); + var x2Symbol = model.GetDeclaredSymbol(x2); + Assert.Equal("System.Int32 x2", x2Symbol.ToTestDisplayString()); + Assert.Equal(SymbolKind.Local, x2Symbol.Kind); + }; + + var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); + + comp.VerifyDiagnostics(); + var verifier = CompileAndVerify(comp, expectedOutput: "hello 42 world", sourceSymbolValidator: validator); + } + + [Fact] + public void DeconstructionInForLoopInScript() + { + var source = +@" +for ((string x1, var (x2, x3)) = (""hello"", (42, ""world"")); ; ) +{ + System.Console.Write($""{x1} {x2} {x3}""); + break; +} +"; + + Action validator = (ModuleSymbol module) => + { + var sourceModule = (SourceModuleSymbol)module; + var compilation = sourceModule.DeclaringCompilation; + var tree = compilation.SyntaxTrees.First(); + var model = compilation.GetSemanticModel(tree); + + var x1 = GetDeconstructionVariable(tree, "x1"); + var x1Symbol = model.GetDeclaredSymbol(x1); + Assert.Equal("System.String x1", x1Symbol.ToTestDisplayString()); + Assert.Equal(SymbolKind.Local, x1Symbol.Kind); + + var x2 = GetDeconstructionVariable(tree, "x2"); + var x2Symbol = model.GetDeclaredSymbol(x2); + Assert.Equal("System.Int32 x2", x2Symbol.ToTestDisplayString()); + Assert.Equal(SymbolKind.Local, x2Symbol.Kind); + }; + + var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); + + comp.VerifyDiagnostics(); + var verifier = CompileAndVerify(comp, expectedOutput: "hello 42 world", sourceSymbolValidator: validator); + } + + [Fact] + public void DeconstructionInCSharp6Script() + { + var source = +@" +var (x, y) = (1, 2); +"; + + var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script.WithLanguageVersion(LanguageVersion.CSharp6), options: TestOptions.DebugExe, references: s_valueTupleRefs); + + comp.VerifyDiagnostics( + // (2,1): error CS8059: Feature 'tuples' is not available in C# 6. Please use language version 7 or greater. + // var (x, y) = (1, 2); + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, "var (x, y)").WithArguments("tuples", "7").WithLocation(2, 1), + // (2,14): error CS8059: Feature 'tuples' is not available in C# 6. Please use language version 7 or greater. + // var (x, y) = (1, 2); + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, "(1, 2)").WithArguments("tuples", "7").WithLocation(2, 14) + ); + } + + [Fact] + public void InvalidDeconstructionInScript() + { + var source = +@" +int (x, y) = (1, 2); +"; + + var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); + comp.VerifyDiagnostics( + // (2,6): error CS8136: Deconstruction 'var (...)' form disallows a specific type for 'var'. + // int (x, y) = (1, 2); + Diagnostic(ErrorCode.ERR_DeconstructionVarFormDisallowsSpecificType, "x").WithLocation(2, 6), + // (2,9): error CS8136: Deconstruction 'var (...)' form disallows a specific type for 'var'. + // int (x, y) = (1, 2); + Diagnostic(ErrorCode.ERR_DeconstructionVarFormDisallowsSpecificType, "y").WithLocation(2, 9) + ); + + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + + var x = GetDeconstructionVariable(tree, "x"); + var xSymbol = model.GetDeclaredSymbol(x); + Assert.Equal("System.Int32 Script.x", xSymbol.ToTestDisplayString()); + var xType = ((FieldSymbol)xSymbol).Type; + Assert.False(xType.IsErrorType()); + Assert.Equal("System.Int32", xType.ToTestDisplayString()); + + var y = GetDeconstructionVariable(tree, "y"); + var ySymbol = model.GetDeclaredSymbol(y); + Assert.Equal("System.Int32 Script.y", ySymbol.ToTestDisplayString()); + var yType = ((FieldSymbol)ySymbol).Type; + Assert.False(yType.IsErrorType()); + Assert.Equal("System.Int32", yType.ToTestDisplayString()); + } + + [Fact] + public void NameConflictInDeconstructionInScript() + { + var source = +@" +int x1; +var (x1, x2) = (1, 2); +System.Console.Write(x1); +"; + + var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); + comp.VerifyDiagnostics( + // (3,6): error CS0102: The type 'Script' already contains a definition for 'x1' + // var (x1, x2) = (1, 2); + Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "x1").WithArguments("Script", "x1").WithLocation(3, 6), + // (4,22): error CS0229: Ambiguity between 'x1' and 'x1' + // System.Console.Write(x1); + Diagnostic(ErrorCode.ERR_AmbigMember, "x1").WithArguments("x1", "x1").WithLocation(4, 22) + ); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + + var firstX1 = tree.GetRoot().DescendantNodes().OfType().Where(d => d.Identifier.ValueText == "x1").Single(); + var firstX1Symbol = model.GetDeclaredSymbol(firstX1); + Assert.Equal("System.Int32 Script.x1", firstX1Symbol.ToTestDisplayString()); + Assert.Equal(SymbolKind.Field, firstX1Symbol.Kind); + + var secondX1 = GetDeconstructionVariable(tree, "x1"); + var secondX1Symbol = model.GetDeclaredSymbol(secondX1); + Assert.Equal("System.Int32 Script.x1", secondX1Symbol.ToTestDisplayString()); + Assert.Equal(SymbolKind.Field, secondX1Symbol.Kind); + + Assert.NotEqual(firstX1Symbol, secondX1Symbol); + } + + [Fact] + public void NameConflictInDeconstructionInScript2() + { + var source = +@" +var (x, y) = (1, 2); +var (z, y) = (1, 2); +"; + + var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); + comp.VerifyDiagnostics( + // (3,9): error CS0102: The type 'Script' already contains a definition for 'y' + // var (z, y) = (1, 2); + Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "y").WithArguments("Script", "y").WithLocation(3, 9) + ); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + + var firstY = tree.GetRoot().DescendantNodes().OfType().Where(d => d.Identifier.ValueText == "y").First(); + var firstYSymbol = model.GetDeclaredSymbol(firstY); + Assert.Equal("System.Int32 Script.y", firstYSymbol.ToTestDisplayString()); + Assert.Equal(SymbolKind.Field, firstYSymbol.Kind); + + var secondY = tree.GetRoot().DescendantNodes().OfType().Where(d => d.Identifier.ValueText == "y").Skip(1).First(); + var secondYSymbol = model.GetDeclaredSymbol(secondY); + Assert.Equal("System.Int32 Script.y", secondYSymbol.ToTestDisplayString()); + Assert.Equal(SymbolKind.Field, secondYSymbol.Kind); + + Assert.NotEqual(firstYSymbol, secondYSymbol); + } + + [Fact] + public void NameConflictInDeconstructionInScript3() + { + var source = +@" +var (x, (y, x)) = (1, (2, ""hello"")); +"; + + var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); + comp.VerifyDiagnostics( + // (2,13): error CS0102: The type 'Script' already contains a definition for 'x' + // var (x, (y, x)) = (1, (2, "hello")); + Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "x").WithArguments("Script", "x").WithLocation(2, 13) + ); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + + var firstX = tree.GetRoot().DescendantNodes().OfType().Where(d => d.Identifier.ValueText == "x").First(); + var firstXSymbol = model.GetDeclaredSymbol(firstX); + Assert.Equal("System.Int32 Script.x", firstXSymbol.ToTestDisplayString()); + Assert.Equal(SymbolKind.Field, firstXSymbol.Kind); + + var secondX = tree.GetRoot().DescendantNodes().OfType().Where(d => d.Identifier.ValueText == "x").Skip(1).First(); + var secondXSymbol = model.GetDeclaredSymbol(secondX); + Assert.Equal("System.String Script.x", secondXSymbol.ToTestDisplayString()); + Assert.Equal(SymbolKind.Field, secondXSymbol.Kind); + + Assert.NotEqual(firstXSymbol, secondXSymbol); + } + + [Fact] + public void UnassignedUsedInDeconstructionInScript() + { + var source = +@" +System.Console.Write(x); +var (x, y) = (1, 2); +"; + + var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); + comp.VerifyDiagnostics(); + CompileAndVerify(comp, expectedOutput: "0"); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + + var x = GetDeconstructionVariable(tree, "x"); + var xSymbol = model.GetDeclaredSymbol(x); + var xRef = GetReference(tree, "x"); + Assert.Equal("System.Int32 Script.x", xSymbol.ToTestDisplayString()); + VerifyModelForDeconstructionField(model, x, xRef); + var xType = ((FieldSymbol)xSymbol).Type; + Assert.False(xType.IsErrorType()); + Assert.Equal("System.Int32", xType.ToTestDisplayString()); + } + + [Fact] + public void FailedInferenceInDeconstructionInScript() + { + var source = +@" +var (x, y) = (1, null); +"; + + var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); + comp.GetDeclarationDiagnostics().Verify( + // (2,6): error CS8130: Cannot infer the type of implicitly-typed deconstruction variable 'x'. + // var (x, y) = (1, null); + Diagnostic(ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable, "x").WithArguments("x").WithLocation(2, 6), + // (2,9): error CS8130: Cannot infer the type of implicitly-typed deconstruction variable 'y'. + // var (x, y) = (1, null); + Diagnostic(ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable, "y").WithArguments("y").WithLocation(2, 9) + ); + + comp.VerifyDiagnostics( + // (2,6): error CS8130: Cannot infer the type of implicitly-typed deconstruction variable 'x'. + // var (x, y) = (1, null); + Diagnostic(ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable, "x").WithArguments("x").WithLocation(2, 6), + // (2,9): error CS8130: Cannot infer the type of implicitly-typed deconstruction variable 'y'. + // var (x, y) = (1, null); + Diagnostic(ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable, "y").WithArguments("y").WithLocation(2, 9) + ); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + + var x = GetDeconstructionVariable(tree, "x"); + var xSymbol = model.GetDeclaredSymbol(x); + Assert.Equal("var Script.x", xSymbol.ToTestDisplayString()); + var xType = ((FieldSymbol)xSymbol).Type; + Assert.True(xType.IsErrorType()); + Assert.Equal("var", xType.ToTestDisplayString()); + + var y = GetDeconstructionVariable(tree, "y"); + var ySymbol = model.GetDeclaredSymbol(y); + Assert.Equal("var Script.y", ySymbol.ToTestDisplayString()); + var yType = ((FieldSymbol)ySymbol).Type; + Assert.True(yType.IsErrorType()); + Assert.Equal("var", yType.ToTestDisplayString()); + } + + [Fact] + public void FailedCircularInferenceInDeconstructionInScript() + { + var source = +@" +var (x1, x2) = (x2, x1); +"; + + var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); + comp.GetDeclarationDiagnostics().Verify( + // (2,10): error CS7019: Type of 'x2' cannot be inferred since its initializer directly or indirectly refers to the definition. + // var (x1, x2) = (x2, x1); + Diagnostic(ErrorCode.ERR_RecursivelyTypedVariable, "x2").WithArguments("x2").WithLocation(2, 10), + // (2,6): error CS7019: Type of 'x1' cannot be inferred since its initializer directly or indirectly refers to the definition. + // var (x1, x2) = (x2, x1); + Diagnostic(ErrorCode.ERR_RecursivelyTypedVariable, "x1").WithArguments("x1").WithLocation(2, 6) + ); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + + var x1 = GetDeconstructionVariable(tree, "x1"); + var x1Symbol = model.GetDeclaredSymbol(x1); + var x1Ref = GetReference(tree, "x1"); + Assert.Equal("var Script.x1", x1Symbol.ToTestDisplayString()); + VerifyModelForDeconstructionField(model, x1, x1Ref); + var x1Type = ((FieldSymbol)x1Symbol).Type; + Assert.True(x1Type.IsErrorType()); + Assert.Equal("var", x1Type.Name); + + var x2 = GetDeconstructionVariable(tree, "x2"); + var x2Symbol = model.GetDeclaredSymbol(x2); + var x2Ref = GetReference(tree, "x2"); + Assert.Equal("var Script.x2", x2Symbol.ToTestDisplayString()); + VerifyModelForDeconstructionField(model, x2, x2Ref); + var x2Type = ((FieldSymbol)x2Symbol).Type; + Assert.True(x2Type.IsErrorType()); + Assert.Equal("var", x2Type.Name); + } + + [Fact] + public void FailedCircularInferenceInDeconstructionInScript2() + { + var source = +@" +var (x1, x2) = (y1, y2); +var (y1, y2) = (x1, x2); +"; + + var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); + comp.GetDeclarationDiagnostics().Verify( + // (3,6): error CS7019: Type of 'y1' cannot be inferred since its initializer directly or indirectly refers to the definition. + // var (y1, y2) = (x1, x2); + Diagnostic(ErrorCode.ERR_RecursivelyTypedVariable, "y1").WithArguments("y1").WithLocation(3, 6), + // (2,6): error CS7019: Type of 'x1' cannot be inferred since its initializer directly or indirectly refers to the definition. + // var (x1, x2) = (y1, y2); + Diagnostic(ErrorCode.ERR_RecursivelyTypedVariable, "x1").WithArguments("x1").WithLocation(2, 6), + // (2,10): error CS7019: Type of 'x2' cannot be inferred since its initializer directly or indirectly refers to the definition. + // var (x1, x2) = (y1, y2); + Diagnostic(ErrorCode.ERR_RecursivelyTypedVariable, "x2").WithArguments("x2").WithLocation(2, 10) + ); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + + var x1 = GetDeconstructionVariable(tree, "x1"); + var x1Symbol = model.GetDeclaredSymbol(x1); + var x1Ref = GetReference(tree, "x1"); + Assert.Equal("var Script.x1", x1Symbol.ToTestDisplayString()); + VerifyModelForDeconstructionField(model, x1, x1Ref); + var x1Type = ((FieldSymbol)x1Symbol).Type; + Assert.True(x1Type.IsErrorType()); + Assert.Equal("var", x1Type.Name); + + var x2 = GetDeconstructionVariable(tree, "x2"); + var x2Symbol = model.GetDeclaredSymbol(x2); + var x2Ref = GetReference(tree, "x2"); + Assert.Equal("var Script.x2", x2Symbol.ToTestDisplayString()); + VerifyModelForDeconstructionField(model, x2, x2Ref); + var x2Type = ((FieldSymbol)x2Symbol).Type; + Assert.True(x2Type.IsErrorType()); + Assert.Equal("var", x2Type.Name); + } + + [Fact] + public void VarAliasInVarDeconstructionInScript() + { + var source = +@" +using var = System.Byte; +var (x1, (x2, x3)) = (1, (2, 3)); +System.Console.Write($""{x1} {x2} {x3}""); +"; + + var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); + comp.VerifyDiagnostics( + // (3,6): error CS8136: Deconstruction 'var (...)' form disallows a specific type for 'var'. + // var (x1, (x2, x3)) = (1, (2, 3)); + Diagnostic(ErrorCode.ERR_DeconstructionVarFormDisallowsSpecificType, "x1").WithLocation(3, 6), + // (3,11): error CS8136: Deconstruction 'var (...)' form disallows a specific type for 'var'. + // var (x1, (x2, x3)) = (1, (2, 3)); + Diagnostic(ErrorCode.ERR_DeconstructionVarFormDisallowsSpecificType, "x2").WithLocation(3, 11), + // (3,15): error CS8136: Deconstruction 'var (...)' form disallows a specific type for 'var'. + // var (x1, (x2, x3)) = (1, (2, 3)); + Diagnostic(ErrorCode.ERR_DeconstructionVarFormDisallowsSpecificType, "x3").WithLocation(3, 15) + ); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + + var x1 = GetDeconstructionVariable(tree, "x1"); + var x1Symbol = model.GetDeclaredSymbol(x1); + var x1Ref = GetReference(tree, "x1"); + Assert.Equal("System.Byte Script.x1", x1Symbol.ToTestDisplayString()); + VerifyModelForDeconstructionField(model, x1, x1Ref); + + var x3 = GetDeconstructionVariable(tree, "x3"); + var x3Symbol = model.GetDeclaredSymbol(x3); + var x3Ref = GetReference(tree, "x3"); + Assert.Equal("System.Byte Script.x3", x3Symbol.ToTestDisplayString()); + VerifyModelForDeconstructionField(model, x3, x3Ref); + + // extra check on var + var x123Var = (TypedVariableComponentSyntax)x1.Parent.Parent; + Assert.Equal("var", x123Var.Type.ToString()); + Assert.Null(model.GetSymbolInfo(x123Var.Type).Symbol); // The var in `var (x1, x2)` has no symbol + } + + [Fact] + public void VarTypeInVarDeconstructionInScript() + { + var source = +@" +class var +{ + public static implicit operator var(int i) { return null; } +} +var (x1, (x2, x3)) = (1, (2, 3)); +System.Console.Write($""{x1} {x2} {x3}""); +"; + + var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); + comp.VerifyDiagnostics( + // (6,6): error CS8136: Deconstruction 'var (...)' form disallows a specific type for 'var'. + // var (x1, (x2, x3)) = (1, (2, 3)); + Diagnostic(ErrorCode.ERR_DeconstructionVarFormDisallowsSpecificType, "x1").WithLocation(6, 6), + // (6,11): error CS8136: Deconstruction 'var (...)' form disallows a specific type for 'var'. + // var (x1, (x2, x3)) = (1, (2, 3)); + Diagnostic(ErrorCode.ERR_DeconstructionVarFormDisallowsSpecificType, "x2").WithLocation(6, 11), + // (6,15): error CS8136: Deconstruction 'var (...)' form disallows a specific type for 'var'. + // var (x1, (x2, x3)) = (1, (2, 3)); + Diagnostic(ErrorCode.ERR_DeconstructionVarFormDisallowsSpecificType, "x3").WithLocation(6, 15) + ); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + + var x1 = GetDeconstructionVariable(tree, "x1"); + var x1Symbol = model.GetDeclaredSymbol(x1); + var x1Ref = GetReference(tree, "x1"); + Assert.Equal("Script.var Script.x1", x1Symbol.ToTestDisplayString()); + VerifyModelForDeconstructionField(model, x1, x1Ref); + + var x3 = GetDeconstructionVariable(tree, "x3"); + var x3Symbol = model.GetDeclaredSymbol(x3); + var x3Ref = GetReference(tree, "x3"); + Assert.Equal("Script.var Script.x3", x3Symbol.ToTestDisplayString()); + VerifyModelForDeconstructionField(model, x3, x3Ref); + + // extra check on var + var x123Var = (TypedVariableComponentSyntax)x1.Parent.Parent; + Assert.Equal("var", x123Var.Type.ToString()); + Assert.Null(model.GetSymbolInfo(x123Var.Type).Symbol); // The var in `var (x1, x2)` has no symbol + } + + [Fact] + public void VarAliasInTypedDeconstructionInScript() + { + var source = +@" +using var = System.Byte; +(var x1, (var x2, var x3)) = (1, (2, 3)); +System.Console.Write($""{x1} {x2} {x3}""); +"; + + var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); + comp.VerifyDiagnostics(); + CompileAndVerify(comp, expectedOutput: "1 2 3"); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + + var x1 = GetDeconstructionVariable(tree, "x1"); + var x1Symbol = model.GetDeclaredSymbol(x1); + var x1Ref = GetReference(tree, "x1"); + Assert.Equal("System.Byte Script.x1", x1Symbol.ToTestDisplayString()); + VerifyModelForDeconstructionField(model, x1, x1Ref); + + var x3 = GetDeconstructionVariable(tree, "x3"); + var x3Symbol = model.GetDeclaredSymbol(x3); + var x3Ref = GetReference(tree, "x3"); + Assert.Equal("System.Byte Script.x3", x3Symbol.ToTestDisplayString()); + VerifyModelForDeconstructionField(model, x3, x3Ref); + + // extra checks on x1's var + var x1Type = GetTypeSyntax(x1); + Assert.Equal(SymbolKind.NamedType, model.GetSymbolInfo(x1Type).Symbol.Kind); + Assert.Equal("byte", model.GetSymbolInfo(x1Type).Symbol.ToDisplayString()); + var x1Alias = model.GetAliasInfo(x1Type); + Assert.Equal(SymbolKind.NamedType, x1Alias.Target.Kind); + Assert.Equal("byte", x1Alias.Target.ToDisplayString()); + + // extra checks on x3's var + var x3Type = GetTypeSyntax(x3); + Assert.Equal(SymbolKind.NamedType, model.GetSymbolInfo(x3Type).Symbol.Kind); + Assert.Equal("byte", model.GetSymbolInfo(x3Type).Symbol.ToDisplayString()); + var x3Alias = model.GetAliasInfo(x3Type); + Assert.Equal(SymbolKind.NamedType, x3Alias.Target.Kind); + Assert.Equal("byte", x3Alias.Target.ToDisplayString()); + } + + [Fact] + public void VarTypeInTypedDeconstructionInScript() + { + var source = +@" +class var +{ + public static implicit operator var(int i) { return new var(); } + public override string ToString() { return ""var""; } +} +(var x1, (var x2, var x3)) = (1, (2, 3)); +System.Console.Write($""{x1} {x2} {x3}""); +"; + + var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); + comp.VerifyDiagnostics(); + CompileAndVerify(comp, expectedOutput: "var var var"); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + + var x1 = GetDeconstructionVariable(tree, "x1"); + var x1Symbol = model.GetDeclaredSymbol(x1); + var x1Ref = GetReference(tree, "x1"); + Assert.Equal("Script.var Script.x1", x1Symbol.ToTestDisplayString()); + VerifyModelForDeconstructionField(model, x1, x1Ref); + + var x3 = GetDeconstructionVariable(tree, "x3"); + var x3Symbol = model.GetDeclaredSymbol(x3); + var x3Ref = GetReference(tree, "x3"); + Assert.Equal("Script.var Script.x3", x3Symbol.ToTestDisplayString()); + VerifyModelForDeconstructionField(model, x3, x3Ref); + + // extra checks on x1's var + var x1Type = GetTypeSyntax(x1); + Assert.Equal(SymbolKind.NamedType, model.GetSymbolInfo(x1Type).Symbol.Kind); + Assert.Equal("var", model.GetSymbolInfo(x1Type).Symbol.ToDisplayString()); + Assert.Null(model.GetAliasInfo(x1Type)); + + // extra checks on x3's var + var x3Type = GetTypeSyntax(x3); + Assert.Equal(SymbolKind.NamedType, model.GetSymbolInfo(x3Type).Symbol.Kind); + Assert.Equal("var", model.GetSymbolInfo(x3Type).Symbol.ToDisplayString()); + Assert.Null(model.GetAliasInfo(x3Type)); + } } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/DeconstructionTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/DeconstructionTests.cs index 4a0e75cb89a32fb07fa27b35dda6cfb9d892f149..165e469b9f6aff4f18b3952a79c30ecae5d060c1 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/DeconstructionTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/DeconstructionTests.cs @@ -1325,6 +1325,7 @@ static void Main() var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, parseOptions: TestOptions.Regular6); comp.VerifyDiagnostics( + // (6,9): error CS8059: Feature 'tuples' is not available in C# 6. Please use language version 7 or greater. // var (x1, x2) = Pair.Create(1, 2); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, "var (x1, x2)").WithArguments("tuples", "7").WithLocation(6, 9), // (7,9): error CS8059: Feature 'tuples' is not available in C# 6. Please use language version 7 or greater. @@ -1335,7 +1336,19 @@ static void Main() Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, "(int x5, var (x6, x7))").WithArguments("tuples", "7").WithLocation(8, 18), // (9,14): error CS8059: Feature 'tuples' is not available in C# 6. Please use language version 7 or greater. // for ((int x8, var (x9, x10)) = Pair.Create(1, Pair.Create(2, 3)); ; ) { } - Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, "(int x8, var (x9, x10))").WithArguments("tuples", "7").WithLocation(9, 14) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, "(int x8, var (x9, x10))").WithArguments("tuples", "7").WithLocation(9, 14), + // (8,32): error CS8130: Cannot infer the type of implicitly-typed deconstruction variable 'x6'. + // foreach ((int x5, var (x6, x7)) in new[] { Pair.Create(1, Pair.Create(2, 3)) }) { } + Diagnostic(ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable, "x6").WithArguments("x6").WithLocation(8, 32), + // (8,36): error CS8130: Cannot infer the type of implicitly-typed deconstruction variable 'x7'. + // foreach ((int x5, var (x6, x7)) in new[] { Pair.Create(1, Pair.Create(2, 3)) }) { } + Diagnostic(ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable, "x7").WithArguments("x7").WithLocation(8, 36), + // (9,28): error CS8130: Cannot infer the type of implicitly-typed deconstruction variable 'x9'. + // for ((int x8, var (x9, x10)) = Pair.Create(1, Pair.Create(2, 3)); ; ) { } + Diagnostic(ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable, "x9").WithArguments("x9").WithLocation(9, 28), + // (9,32): error CS8130: Cannot infer the type of implicitly-typed deconstruction variable 'x10'. + // for ((int x8, var (x9, x10)) = Pair.Create(1, Pair.Create(2, 3)); ; ) { } + Diagnostic(ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable, "x10").WithArguments("x10").WithLocation(9, 32) ); } @@ -1535,7 +1548,13 @@ static void Main() comp.VerifyDiagnostics( // (6,24): error CS8131: Deconstruct assignment requires an expression with a type on the right-hand-side. // var (x1, x2) = null; - Diagnostic(ErrorCode.ERR_DeconstructRequiresExpression, "null").WithLocation(6, 24) + Diagnostic(ErrorCode.ERR_DeconstructRequiresExpression, "null").WithLocation(6, 24), + // (6,14): error CS8130: Cannot infer the type of implicitly-typed deconstruction variable 'x1'. + // var (x1, x2) = null; + Diagnostic(ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable, "x1").WithArguments("x1").WithLocation(6, 14), + // (6,18): error CS8130: Cannot infer the type of implicitly-typed deconstruction variable 'x2'. + // var (x1, x2) = null; + Diagnostic(ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable, "x2").WithArguments("x2").WithLocation(6, 18) ); } @@ -1553,9 +1572,12 @@ static void Main() "; var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( - // (6,9): error CS8130: The type information on the left-hand-side 'x2' and right-hand-side 'null' of the deconstruction was insufficient to infer a merged type. + // (6,14): error CS8130: Cannot infer the type of implicitly-typed deconstruction variable 'x1'. // var (x1, x2) = (1, null); - Diagnostic(ErrorCode.ERR_DeconstructCouldNotInferMergedType, "var (x1, x2) = (1, null);").WithArguments("x2", "null").WithLocation(6, 9) + Diagnostic(ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable, "x1").WithArguments("x1").WithLocation(6, 14), + // (6,18): error CS8130: Cannot infer the type of implicitly-typed deconstruction variable 'x2'. + // var (x1, x2) = (1, null); + Diagnostic(ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable, "x2").WithArguments("x2").WithLocation(6, 18) ); } @@ -1573,12 +1595,12 @@ static void Main() "; var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( - // (6,9): error CS8130: The type information on the left-hand-side 'x3' and right-hand-side 'null' of the deconstruction was insufficient to infer a merged type. + // (6,35): error CS8130: Cannot infer the type of implicitly-typed deconstruction variable 'x3'. // (string x1, (byte x2, var x3), var x4) = (null, (2, null), null); - Diagnostic(ErrorCode.ERR_DeconstructCouldNotInferMergedType, "(string x1, (byte x2, var x3), var x4) = (null, (2, null), null);").WithArguments("x3", "null").WithLocation(6, 9), - // (6,9): error CS8130: The type information on the left-hand-side 'x4' and right-hand-side 'null' of the deconstruction was insufficient to infer a merged type. + Diagnostic(ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable, "x3").WithArguments("x3").WithLocation(6, 35), + // (6,44): error CS8130: Cannot infer the type of implicitly-typed deconstruction variable 'x4'. // (string x1, (byte x2, var x3), var x4) = (null, (2, null), null); - Diagnostic(ErrorCode.ERR_DeconstructCouldNotInferMergedType, "(string x1, (byte x2, var x3), var x4) = (null, (2, null), null);").WithArguments("x4", "null").WithLocation(6, 9) + Diagnostic(ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable, "x4").WithArguments("x4").WithLocation(6, 44) ); } @@ -1598,7 +1620,10 @@ static void Main() comp.VerifyDiagnostics( // (6,51): error CS8131: Deconstruct assignment requires an expression with a type on the right-hand-side. // ((string x1, byte x2, var x3), int x4) = (null, 4); - Diagnostic(ErrorCode.ERR_DeconstructRequiresExpression, "null").WithLocation(6, 51) + Diagnostic(ErrorCode.ERR_DeconstructRequiresExpression, "null").WithLocation(6, 51), + // (6,35): error CS8130: Cannot infer the type of implicitly-typed deconstruction variable 'x3'. + // ((string x1, byte x2, var x3), int x4) = (null, 4); + Diagnostic(ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable, "x3").WithArguments("x3").WithLocation(6, 35) ); } @@ -1616,9 +1641,9 @@ static void Main() "; var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( - // (6,9): error CS8130: The type information on the left-hand-side 'x2' and right-hand-side '(null, 2)' of the deconstruction was insufficient to infer a merged type. + // (6,25): error CS8130: Cannot infer the type of implicitly-typed deconstruction variable 'x2'. // (string x1, var x2) = (null, (null, 2)); - Diagnostic(ErrorCode.ERR_DeconstructCouldNotInferMergedType, "(string x1, var x2) = (null, (null, 2));").WithArguments("x2", "(null, 2)").WithLocation(6, 9) + Diagnostic(ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable, "x2").WithArguments("x2").WithLocation(6, 25) ); } @@ -1662,7 +1687,10 @@ static void Main() Diagnostic(ErrorCode.ERR_DeconstructWrongCardinality, @"(string x1, var y1) = (null, ""hello"", 3);").WithArguments("3", "2").WithLocation(6, 9), // (7,47): error CS8131: Deconstruct assignment requires an expression with a type on the right-hand-side. // (string x2, var y2) = (null, "hello", null); - Diagnostic(ErrorCode.ERR_DeconstructRequiresExpression, "null").WithLocation(7, 47) + Diagnostic(ErrorCode.ERR_DeconstructRequiresExpression, "null").WithLocation(7, 47), + // (7,25): error CS8130: Cannot infer the type of implicitly-typed deconstruction variable 'y2'. + // (string x2, var y2) = (null, "hello", null); + Diagnostic(ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable, "y2").WithArguments("y2").WithLocation(7, 25) ); } @@ -1749,7 +1777,13 @@ static void Main() comp.VerifyDiagnostics( // (6,9): error CS8132: Cannot deconstruct a tuple of '3' elements into '2' variables. // (var (x1, x2), var x3) = (1, 2, 3); - Diagnostic(ErrorCode.ERR_DeconstructWrongCardinality, "(var (x1, x2), var x3) = (1, 2, 3);").WithArguments("3", "2").WithLocation(6, 9) + Diagnostic(ErrorCode.ERR_DeconstructWrongCardinality, "(var (x1, x2), var x3) = (1, 2, 3);").WithArguments("3", "2").WithLocation(6, 9), + // (6,15): error CS8130: Cannot infer the type of implicitly-typed deconstruction variable 'x1'. + // (var (x1, x2), var x3) = (1, 2, 3); + Diagnostic(ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable, "x1").WithArguments("x1").WithLocation(6, 15), + // (6,19): error CS8130: Cannot infer the type of implicitly-typed deconstruction variable 'x2'. + // (var (x1, x2), var x3) = (1, 2, 3); + Diagnostic(ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable, "x2").WithArguments("x2").WithLocation(6, 19) ); } @@ -1821,17 +1855,23 @@ static void Main() var comp = CreateCompilationWithMscorlib(source); comp.VerifyDiagnostics( // (9,13): error CS0128: A local variable named 'x' is already defined in this scope - // var(x, y) = 42; + // var(x, y) = 42; // parsed as deconstruction Diagnostic(ErrorCode.ERR_LocalDuplicate, "x").WithArguments("x").WithLocation(9, 13), // (9,16): error CS0128: A local variable named 'y' is already defined in this scope - // var(x, y) = 42; + // var(x, y) = 42; // parsed as deconstruction Diagnostic(ErrorCode.ERR_LocalDuplicate, "y").WithArguments("y").WithLocation(9, 16), // (9,21): error CS1061: 'int' does not contain a definition for 'Deconstruct' and no extension method 'Deconstruct' accepting a first argument of type 'int' could be found (are you missing a using directive or an assembly reference?) - // var(x, y) = 42; + // var(x, y) = 42; // parsed as deconstruction Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "42").WithArguments("int", "Deconstruct").WithLocation(9, 21), // (9,21): error CS8129: No Deconstruct instance or extension method was found for type 'int', with 2 out parameters. - // var(x, y) = 42; + // var(x, y) = 42; // parsed as deconstruction Diagnostic(ErrorCode.ERR_MissingDeconstruct, "42").WithArguments("int", "2").WithLocation(9, 21), + // (9,13): error CS8130: Cannot infer the type of implicitly-typed deconstruction variable 'x'. + // var(x, y) = 42; // parsed as deconstruction + Diagnostic(ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable, "x").WithArguments("x").WithLocation(9, 13), + // (9,16): error CS8130: Cannot infer the type of implicitly-typed deconstruction variable 'y'. + // var(x, y) = 42; // parsed as deconstruction + Diagnostic(ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable, "y").WithArguments("y").WithLocation(9, 16), // (8,13): warning CS0219: The variable 'x' is assigned but its value is never used // int x = 0, y = 0; Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "x").WithArguments("x").WithLocation(8, 13), @@ -2223,7 +2263,13 @@ static void Main() comp.VerifyDiagnostics( // (6,34): error CS1579: foreach statement cannot operate on variables of type 'int' because 'int' does not contain a public definition for 'GetEnumerator' // foreach (var (x1, x2) in 1) - Diagnostic(ErrorCode.ERR_ForEachMissingMember, "1").WithArguments("int", "GetEnumerator").WithLocation(6, 34) + Diagnostic(ErrorCode.ERR_ForEachMissingMember, "1").WithArguments("int", "GetEnumerator").WithLocation(6, 34), + // (6,23): error CS8130: Cannot infer the type of implicitly-typed deconstruction variable 'x1'. + // foreach (var (x1, x2) in 1) + Diagnostic(ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable, "x1").WithArguments("x1").WithLocation(6, 23), + // (6,27): error CS8130: Cannot infer the type of implicitly-typed deconstruction variable 'x2'. + // foreach (var (x1, x2) in 1) + Diagnostic(ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable, "x2").WithArguments("x2").WithLocation(6, 27) ); } @@ -2277,7 +2323,13 @@ static void Main() comp.VerifyDiagnostics( // (6,36): error CS0103: The name 'x1' does not exist in the current context // foreach (var (x1, x2) in M(x1)) { } - Diagnostic(ErrorCode.ERR_NameNotInContext, "x1").WithArguments("x1").WithLocation(6, 36) + Diagnostic(ErrorCode.ERR_NameNotInContext, "x1").WithArguments("x1").WithLocation(6, 36), + // (6,23): error CS8130: Cannot infer the type of implicitly-typed deconstruction variable 'x1'. + // foreach (var (x1, x2) in M(x1)) { } + Diagnostic(ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable, "x1").WithArguments("x1").WithLocation(6, 23), + // (6,27): error CS8130: Cannot infer the type of implicitly-typed deconstruction variable 'x2'. + // foreach (var (x1, x2) in M(x1)) { } + Diagnostic(ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable, "x2").WithArguments("x2").WithLocation(6, 27) ); } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/OutVarTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/OutVarTests.cs index f6b754f55d54836b715add594483c9136ff74a2c..e4a068bf77a8ef36dfaa47d236f51bb68adc4c27 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/OutVarTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/OutVarTests.cs @@ -23103,36 +23103,6 @@ public static bool TakeOutParam(T y, out T x) options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( - // (2,17): error CS1519: Invalid token '=' in class, struct, or interface member declaration - // (bool a, int b) = (H.TakeOutParam(1, out int x1), 1); - Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "=").WithArguments("=").WithLocation(2, 17), - // (2,17): error CS1525: Invalid expression term '=' - // (bool a, int b) = (H.TakeOutParam(1, out int x1), 1); - Diagnostic(ErrorCode.ERR_InvalidExprTerm, "=").WithArguments("=").WithLocation(2, 17), - // (6,17): error CS1519: Invalid token '=' in class, struct, or interface member declaration - // (bool c, int d) = (H.TakeOutParam(2, out int x2), 2); - Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "=").WithArguments("=").WithLocation(6, 17), - // (6,17): error CS1525: Invalid expression term '=' - // (bool c, int d) = (H.TakeOutParam(2, out int x2), 2); - Diagnostic(ErrorCode.ERR_InvalidExprTerm, "=").WithArguments("=").WithLocation(6, 17), - // (8,17): error CS1519: Invalid token '=' in class, struct, or interface member declaration - // (bool e, int f) = (H.TakeOutParam(3, out int x3), 3); - Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "=").WithArguments("=").WithLocation(8, 17), - // (8,17): error CS1525: Invalid expression term '=' - // (bool e, int f) = (H.TakeOutParam(3, out int x3), 3); - Diagnostic(ErrorCode.ERR_InvalidExprTerm, "=").WithArguments("=").WithLocation(8, 17), - // (11,18): error CS1519: Invalid token '=' in class, struct, or interface member declaration - // (bool g, bool h) = (H.TakeOutParam(41, out int x4), - Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "=").WithArguments("=").WithLocation(11, 18), - // (11,18): error CS1525: Invalid expression term '=' - // (bool g, bool h) = (H.TakeOutParam(41, out int x4), - Diagnostic(ErrorCode.ERR_InvalidExprTerm, "=").WithArguments("=").WithLocation(11, 18), - // (14,20): error CS1519: Invalid token '=' in class, struct, or interface member declaration - // (bool x5, bool x6) = (H.TakeOutParam(5, out int x5), - Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "=").WithArguments("=").WithLocation(14, 20), - // (14,20): error CS1525: Invalid expression term '=' - // (bool x5, bool x6) = (H.TakeOutParam(5, out int x5), - Diagnostic(ErrorCode.ERR_InvalidExprTerm, "=").WithArguments("=").WithLocation(14, 20), // (6,46): error CS0102: The type 'Script' already contains a definition for 'x2' // (bool c, int d) = (H.TakeOutParam(2, out int x2), 2); Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "x2").WithArguments("Script", "x2").WithLocation(6, 46), @@ -23142,6 +23112,12 @@ public static bool TakeOutParam(T y, out T x) // (12,48): error CS0102: The type 'Script' already contains a definition for 'x4' // H.TakeOutParam(42, out int x4)); Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "x4").WithArguments("Script", "x4").WithLocation(12, 48), + // (14,49): error CS0102: The type 'Script' already contains a definition for 'x5' + // (bool x5, bool x6) = (H.TakeOutParam(5, out int x5), + Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "x5").WithArguments("Script", "x5").WithLocation(14, 49), + // (15,49): error CS0102: The type 'Script' already contains a definition for 'x6' + // H.TakeOutParam(6, out int x6)); + Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "x6").WithArguments("Script", "x6").WithLocation(15, 49), // (19,17): error CS0229: Ambiguity between 'x2' and 'x2' // H.Dummy(x1, x2, x3, x4, x5, x6); Diagnostic(ErrorCode.ERR_AmbigMember, "x2").WithArguments("x2", "x2").WithLocation(19, 17), @@ -23150,7 +23126,13 @@ public static bool TakeOutParam(T y, out T x) Diagnostic(ErrorCode.ERR_AmbigMember, "x3").WithArguments("x3", "x3").WithLocation(19, 21), // (19,25): error CS0229: Ambiguity between 'x4' and 'x4' // H.Dummy(x1, x2, x3, x4, x5, x6); - Diagnostic(ErrorCode.ERR_AmbigMember, "x4").WithArguments("x4", "x4").WithLocation(19, 25) + Diagnostic(ErrorCode.ERR_AmbigMember, "x4").WithArguments("x4", "x4").WithLocation(19, 25), + // (19,29): error CS0229: Ambiguity between 'x5' and 'x5' + // H.Dummy(x1, x2, x3, x4, x5, x6); + Diagnostic(ErrorCode.ERR_AmbigMember, "x5").WithArguments("x5", "x5").WithLocation(19, 29), + // (19,33): error CS0229: Ambiguity between 'x6' and 'x6' + // H.Dummy(x1, x2, x3, x4, x5, x6); + Diagnostic(ErrorCode.ERR_AmbigMember, "x6").WithArguments("x6", "x6").WithLocation(19, 33) ); var tree = compilation.SyntaxTrees.Single(); @@ -23177,13 +23159,13 @@ public static bool TakeOutParam(T y, out T x) var x5Decl = GetOutVarDeclarations(tree, "x5").Single(); var x5Ref = GetReferences(tree, "x5").ToArray(); - Assert.Equal(2, x5Ref.Length); - VerifyModelForOutField(model, x5Decl, x5Ref[1]); + Assert.Equal(1, x5Ref.Length); + VerifyModelForOutFieldDuplicate(model, x5Decl, x5Ref[0]); var x6Decl = GetOutVarDeclarations(tree, "x6").Single(); var x6Ref = GetReferences(tree, "x6").ToArray(); - Assert.Equal(2, x6Ref.Length); - VerifyModelForOutField(model, x6Decl, x6Ref[1]); + Assert.Equal(1, x6Ref.Length); + VerifyModelForOutFieldDuplicate(model, x6Decl, x6Ref[0]); } { @@ -24016,6 +23998,12 @@ public static bool TakeOutParam(T y, out T x) // (12,48): error CS0102: The type 'Script' already contains a definition for 'x4' // H.TakeOutParam(42, out int x4)); Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "x4").WithArguments("Script", "x4").WithLocation(12, 48), + // (14,49): error CS0102: The type 'Script' already contains a definition for 'x5' + // (bool x5, bool x6) = (H.TakeOutParam(5, out int x5), + Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "x5").WithArguments("Script", "x5").WithLocation(14, 49), + // (15,49): error CS0102: The type 'Script' already contains a definition for 'x6' + // H.TakeOutParam(6, out int x6)); + Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "x6").WithArguments("Script", "x6").WithLocation(15, 49), // (1,1): warning CS0164: This label has not been referenced // l1: Diagnostic(ErrorCode.WRN_UnreferencedLabel, "l1").WithLocation(1, 1), @@ -24039,7 +24027,13 @@ public static bool TakeOutParam(T y, out T x) Diagnostic(ErrorCode.ERR_AmbigMember, "x3").WithArguments("x3", "x3").WithLocation(19, 21), // (19,25): error CS0229: Ambiguity between 'x4' and 'x4' // H.Dummy(x1, x2, x3, x4, x5, x6); - Diagnostic(ErrorCode.ERR_AmbigMember, "x4").WithArguments("x4", "x4").WithLocation(19, 25) + Diagnostic(ErrorCode.ERR_AmbigMember, "x4").WithArguments("x4", "x4").WithLocation(19, 25), + // (19,29): error CS0229: Ambiguity between 'x5' and 'x5' + // H.Dummy(x1, x2, x3, x4, x5, x6); + Diagnostic(ErrorCode.ERR_AmbigMember, "x5").WithArguments("x5", "x5").WithLocation(19, 29), + // (19,33): error CS0229: Ambiguity between 'x6' and 'x6' + // H.Dummy(x1, x2, x3, x4, x5, x6); + Diagnostic(ErrorCode.ERR_AmbigMember, "x6").WithArguments("x6", "x6").WithLocation(19, 33) ); var tree = compilation.SyntaxTrees.Single(); @@ -24067,12 +24061,12 @@ public static bool TakeOutParam(T y, out T x) var x5Decl = GetOutVarDeclarations(tree, "x5").Single(); var x5Ref = GetReferences(tree, "x5").ToArray(); Assert.Equal(1, x5Ref.Length); - VerifyModelForOutField(model, x5Decl, x5Ref); + VerifyModelForOutFieldDuplicate(model, x5Decl, x5Ref); var x6Decl = GetOutVarDeclarations(tree, "x6").Single(); var x6Ref = GetReferences(tree, "x6").ToArray(); Assert.Equal(1, x6Ref.Length); - VerifyModelForOutField(model, x6Decl, x6Ref); + VerifyModelForOutFieldDuplicate(model, x6Decl, x6Ref); } { @@ -24171,6 +24165,12 @@ public static bool TakeOutParam(T y, out T x) // (12,48): error CS0102: The type 'Script' already contains a definition for 'x4' // H.TakeOutParam(42, out var x4)); Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "x4").WithArguments("Script", "x4").WithLocation(12, 48), + // (14,49): error CS0102: The type 'Script' already contains a definition for 'x5' + // (bool x5, bool x6) = (H.TakeOutParam(5, out var x5), + Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "x5").WithArguments("Script", "x5").WithLocation(14, 49), + // (15,49): error CS0102: The type 'Script' already contains a definition for 'x6' + // H.TakeOutParam(6, out var x6)); + Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "x6").WithArguments("Script", "x6").WithLocation(15, 49), // (1,1): warning CS0164: This label has not been referenced // l1: Diagnostic(ErrorCode.WRN_UnreferencedLabel, "l1").WithLocation(1, 1), @@ -24194,7 +24194,13 @@ public static bool TakeOutParam(T y, out T x) Diagnostic(ErrorCode.ERR_AmbigMember, "x3").WithArguments("x3", "x3").WithLocation(19, 21), // (19,25): error CS0229: Ambiguity between 'x4' and 'x4' // H.Dummy(x1, x2, x3, x4, x5, x6); - Diagnostic(ErrorCode.ERR_AmbigMember, "x4").WithArguments("x4", "x4").WithLocation(19, 25) + Diagnostic(ErrorCode.ERR_AmbigMember, "x4").WithArguments("x4", "x4").WithLocation(19, 25), + // (19,29): error CS0229: Ambiguity between 'x5' and 'x5' + // H.Dummy(x1, x2, x3, x4, x5, x6); + Diagnostic(ErrorCode.ERR_AmbigMember, "x5").WithArguments("x5", "x5").WithLocation(19, 29), + // (19,33): error CS0229: Ambiguity between 'x6' and 'x6' + // H.Dummy(x1, x2, x3, x4, x5, x6); + Diagnostic(ErrorCode.ERR_AmbigMember, "x6").WithArguments("x6", "x6").WithLocation(19, 33) ); var tree = compilation.SyntaxTrees.Single(); @@ -24222,12 +24228,12 @@ public static bool TakeOutParam(T y, out T x) var x5Decl = GetOutVarDeclarations(tree, "x5").Single(); var x5Ref = GetReferences(tree, "x5").ToArray(); Assert.Equal(1, x5Ref.Length); - VerifyModelForOutField(model, x5Decl, x5Ref); + VerifyModelForOutFieldDuplicate(model, x5Decl, x5Ref); var x6Decl = GetOutVarDeclarations(tree, "x6").Single(); var x6Ref = GetReferences(tree, "x6").ToArray(); Assert.Equal(1, x6Ref.Length); - VerifyModelForOutField(model, x6Decl, x6Ref); + VerifyModelForOutFieldDuplicate(model, x6Decl, x6Ref); } { diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/DeconstructionTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/DeconstructionTests.cs index 46925da1685b0534db34ef9f6eaf69762f615387..3ab6d1df5af1a4b8e204da7a1f5fb7aa88781203 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/DeconstructionTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/DeconstructionTests.cs @@ -1538,6 +1538,169 @@ void Foo() EOF(); } + [Fact] + public void DeconstructionInScript() + { + var tree = UsingTree(@" (int x, int y) = (1, 2); ", options: TestOptions.Script); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.DeconstructionDeclarationStatement); + { + N(SyntaxKind.VariableComponentAssignment); + { + N(SyntaxKind.ParenthesizedVariableComponent); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.TypedVariableComponent); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.SingleVariableDesignation); + { + N(SyntaxKind.IdentifierToken, "x"); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.TypedVariableComponent); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.SingleVariableDesignation); + { + N(SyntaxKind.IdentifierToken, "y"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.EqualsToken); + N(SyntaxKind.TupleExpression); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Argument); + { + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.Argument); + { + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken); + } + } + N(SyntaxKind.CloseParenToken); + } + } + N(SyntaxKind.SemicolonToken); + } + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void DeconstructionForEachInScript() + { + var tree = UsingTree(@" foreach ((int x, int y) in new[] { (1, 2) }) { }; ", options: TestOptions.Script); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.ForEachComponentStatement); + { + N(SyntaxKind.ForEachKeyword); + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.ParenthesizedVariableComponent); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.TypedVariableComponent); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.SingleVariableDesignation); + { + N(SyntaxKind.IdentifierToken, "x"); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.TypedVariableComponent); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.SingleVariableDesignation); + { + N(SyntaxKind.IdentifierToken, "y"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.InKeyword); + N(SyntaxKind.ImplicitArrayCreationExpression); + { + N(SyntaxKind.NewKeyword); + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.CloseBracketToken); + N(SyntaxKind.ArrayInitializerExpression); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.TupleExpression); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Argument); + { + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.Argument); + { + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseParenToken); + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + } + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.EmptyStatement); + { + N(SyntaxKind.SemicolonToken); + } + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + [Fact] public void TupleArray() {