From 1c53b7e82fb949bc34ff900ba6b60ff62a66b903 Mon Sep 17 00:00:00 2001 From: Julien Date: Thu, 30 Jun 2016 15:55:28 -0700 Subject: [PATCH] Binding for deconstruction-declaration in 'for' statement (#12302) --- .../Portable/Binder/Binder_Deconstruct.cs | 19 +- .../Portable/Binder/Binder_Statements.cs | 8 +- .../CSharp/Portable/Binder/ForLoopBinder.cs | 38 +- .../Portable/Binder/LocalScopeBinder.cs | 13 +- .../Compilation/CSharpSemanticModel.cs | 8 +- .../CSharp/Portable/PublicAPI.Unshipped.txt | 1 + .../Symbols/Source/SourceLocalSymbol.cs | 25 +- .../CSharp/Portable/Syntax/SyntaxFacts.cs | 2 +- .../Syntax/VariableDeclarationSyntax.cs | 2 + .../Emit/CodeGen/CodeGenDeconstructTests.cs | 565 ++++++++++++++---- .../Test/Emit/CodeGen/CodeGenTupleTest.cs | 5 + 11 files changed, 544 insertions(+), 142 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Deconstruct.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Deconstruct.cs index d7dc3205ae533..bc9b70073786f 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Deconstruct.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Deconstruct.cs @@ -479,13 +479,14 @@ private BoundExpression MissingDeconstruct(BoundExpression receiver, ExpressionS return BadExpression(syntax, childNode); } - private BoundLocalDeconstructionDeclaration BindDeconstructionDeclarationStatementParts(LocalDeclarationStatementSyntax node, DiagnosticBag diagnostics) + internal BoundLocalDeconstructionDeclaration BindDeconstructionDeclaration(CSharpSyntaxNode node, VariableDeclarationSyntax declaration, DiagnosticBag diagnostics) { - Debug.Assert(node.Declaration.Deconstruction != null); + Debug.Assert(node.Kind() == SyntaxKind.LocalDeclarationStatement || node.Kind() == SyntaxKind.VariableDeclaration); + Debug.Assert(declaration.IsDeconstructionDeclaration); - ArrayBuilder variables = BindDeconstructionDeclarationVariables(node.Declaration, node.Declaration.Type, diagnostics); + ArrayBuilder variables = BindDeconstructionDeclarationVariables(declaration, declaration.Type, diagnostics); - var result = new BoundLocalDeconstructionDeclaration(node, BindDeconstructionAssignment(node.Declaration.Deconstruction.Value, node.Declaration.Deconstruction.Value, variables, diagnostics)); + var result = new BoundLocalDeconstructionDeclaration(node, BindDeconstructionAssignment(declaration.Deconstruction.Value, declaration.Deconstruction.Value, variables, diagnostics)); FreeDeconstructionVariables(variables); return result; @@ -499,7 +500,7 @@ private BoundLocalDeconstructionDeclaration BindDeconstructionDeclarationStateme /// private ArrayBuilder BindDeconstructionDeclarationVariables(VariableDeclarationSyntax node, TypeSyntax closestTypeSyntax, DiagnosticBag diagnostics) { - Debug.Assert(node.Deconstruction != null); + Debug.Assert(node.IsDeconstructionDeclaration); SeparatedSyntaxList variables = node.Deconstruction.Variables; // There are four cases for VariableDeclaration: @@ -514,13 +515,13 @@ private ArrayBuilder BindDeconstructionDeclarationVariab TypeSyntax typeSyntax = variable.Type ?? closestTypeSyntax; DeconstructionVariable local; - if (variable.Deconstruction == null) + if (variable.IsDeconstructionDeclaration) { - local = new DeconstructionVariable(BindDeconstructionDeclarationVariable(variable, typeSyntax, diagnostics)); + local = new DeconstructionVariable(BindDeconstructionDeclarationVariables(variable, typeSyntax, diagnostics)); } else { - local = new DeconstructionVariable(BindDeconstructionDeclarationVariables(variable, typeSyntax, diagnostics)); + local = new DeconstructionVariable(BindDeconstructionDeclarationVariable(variable, typeSyntax, diagnostics)); } localsBuilder.Add(local); @@ -534,7 +535,7 @@ private ArrayBuilder BindDeconstructionDeclarationVariab /// private BoundExpression BindDeconstructionDeclarationVariable(VariableDeclarationSyntax node, TypeSyntax closestTypeSyntax, DiagnosticBag diagnostics) { - Debug.Assert(node.Deconstruction == null); + Debug.Assert(!node.IsDeconstructionDeclaration); Debug.Assert(node.Variables.Count == 1); var declarator = node.Variables[0]; diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs index 849183ae43a4a..983d561dbcf85 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs @@ -550,13 +550,13 @@ internal BoundStatement BindLocalDeclarationStatement(LocalDeclarationStatementS Debug.Assert(binder != null); BoundStatement bound; - if (node.Declaration.Deconstruction == null) + if (node.Declaration.IsDeconstructionDeclaration) { - bound = binder.BindDeclarationStatementParts(node, diagnostics); + bound = binder.BindDeconstructionDeclaration(node, node.Declaration, diagnostics); } else { - bound = binder.BindDeconstructionDeclarationStatementParts(node, diagnostics); + bound = binder.BindDeclarationStatementParts(node, diagnostics); } return binder.WrapWithVariablesIfAny(node, bound); @@ -2993,7 +2993,7 @@ internal virtual BoundDoStatement BindDoParts(DiagnosticBag diagnostics, Binder return this.Next.BindDoParts(diagnostics, originalBinder); } - private BoundForStatement BindFor(ForStatementSyntax node, DiagnosticBag diagnostics) + internal BoundForStatement BindFor(ForStatementSyntax node, DiagnosticBag diagnostics) { var loopBinder = this.GetBinder(node); Debug.Assert(loopBinder != null); diff --git a/src/Compilers/CSharp/Portable/Binder/ForLoopBinder.cs b/src/Compilers/CSharp/Portable/Binder/ForLoopBinder.cs index d3e6fb0b7a19f..8f93b184d3d75 100644 --- a/src/Compilers/CSharp/Portable/Binder/ForLoopBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/ForLoopBinder.cs @@ -27,21 +27,28 @@ override protected ImmutableArray BuildLocals() var declaration = _syntax.Declaration; if (declaration != null) { - var refKind = _syntax.RefKeyword.Kind().GetRefKind(); - - foreach (var variable in declaration.Variables) + if (!declaration.IsDeconstructionDeclaration) { - var localSymbol = MakeLocal(refKind, - declaration, - variable, - LocalDeclarationKind.ForInitializerVariable); - locals.Add(localSymbol); + var refKind = _syntax.RefKeyword.Kind().GetRefKind(); - if (variable.Initializer != null) + foreach (var variable in declaration.Variables) { - PatternVariableFinder.FindPatternVariables(this, locals, variable.Initializer.Value); + var localSymbol = MakeLocal(refKind, + declaration, + variable, + LocalDeclarationKind.ForInitializerVariable); + locals.Add(localSymbol); + + if (variable.Initializer != null) + { + PatternVariableFinder.FindPatternVariables(this, locals, variable.Initializer.Value); + } } } + else + { + CollectLocalsFromDeconstruction(declaration, declaration.Type, LocalDeclarationKind.ForInitializerVariable, locals); + } } else { @@ -70,8 +77,15 @@ private BoundForStatement BindForParts(ForStatementSyntax node, Binder originalB if (node.Declaration != null) { Debug.Assert(node.Initializers.Count == 0); - ImmutableArray unused; - initializer = originalBinder.BindForOrUsingOrFixedDeclarations(node.Declaration, LocalDeclarationKind.ForInitializerVariable, diagnostics, out unused); + if (node.Declaration.IsDeconstructionDeclaration) + { + initializer = originalBinder.BindDeconstructionDeclaration(node.Declaration, node.Declaration, diagnostics); + } + else + { + ImmutableArray unused; + initializer = originalBinder.BindForOrUsingOrFixedDeclarations(node.Declaration, LocalDeclarationKind.ForInitializerVariable, diagnostics, out unused); + } } else { diff --git a/src/Compilers/CSharp/Portable/Binder/LocalScopeBinder.cs b/src/Compilers/CSharp/Portable/Binder/LocalScopeBinder.cs index 5102f8e20f46c..09e15cd76185d 100644 --- a/src/Compilers/CSharp/Portable/Binder/LocalScopeBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/LocalScopeBinder.cs @@ -163,7 +163,7 @@ protected ImmutableArray BuildLocals(SyntaxList st locals = ArrayBuilder.GetInstance(); } - if (decl.Declaration.Deconstruction == null) + if (!decl.Declaration.IsDeconstructionDeclaration) { RefKind refKind = decl.RefKeyword.Kind().GetRefKind(); LocalDeclarationKind kind = decl.IsConst ? LocalDeclarationKind.Constant : LocalDeclarationKind.RegularVariable; @@ -176,7 +176,7 @@ protected ImmutableArray BuildLocals(SyntaxList st } else { - CollectLocalsFromDeconstruction(decl.Declaration, decl.Declaration.Type, locals); + CollectLocalsFromDeconstruction(decl.Declaration, decl.Declaration.Type, LocalDeclarationKind.RegularVariable, locals); } } break; @@ -192,13 +192,13 @@ protected ImmutableArray BuildLocals(SyntaxList st // When a VariableDeclaration is used in a deconstruction, there are two cases: // - deconstruction is set, type may be set (for "var"), and no declarators. For instance, `var (x, ...)` or `(int x, ...)`. // - deconstruction is null, type may be set, and there is one declarator holding the identifier. For instance, `int x` or `x`. - private void CollectLocalsFromDeconstruction(VariableDeclarationSyntax declaration, TypeSyntax closestTypeSyntax, ArrayBuilder locals) + internal void CollectLocalsFromDeconstruction(VariableDeclarationSyntax declaration, TypeSyntax closestTypeSyntax, LocalDeclarationKind kind, ArrayBuilder locals) { - if (declaration.Deconstruction != null) + if (declaration.IsDeconstructionDeclaration) { foreach (var variable in declaration.Deconstruction.Variables) { - CollectLocalsFromDeconstruction(variable, variable.Type ?? closestTypeSyntax, locals); + CollectLocalsFromDeconstruction(variable, variable.Type ?? closestTypeSyntax, kind, locals); } } else @@ -210,7 +210,8 @@ private void CollectLocalsFromDeconstruction(VariableDeclarationSyntax declarati this.ContainingMemberOrLambda, this, closestTypeSyntax, - declarator.Identifier); + declarator.Identifier, + kind); locals.Add(localSymbol); } diff --git a/src/Compilers/CSharp/Portable/Compilation/CSharpSemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/CSharpSemanticModel.cs index 94248f8b656f5..e81d2e7f09dee 100644 --- a/src/Compilers/CSharp/Portable/Compilation/CSharpSemanticModel.cs +++ b/src/Compilers/CSharp/Portable/Compilation/CSharpSemanticModel.cs @@ -527,9 +527,13 @@ internal virtual IOperation GetOperationWorker(CSharpSyntaxNode node, GetOperati } else if (SyntaxFacts.IsDeconstructionType(expression, out parent)) { - Debug.Assert(((VariableDeclarationSyntax)parent).Variables.Count == 1); + var declaration = (VariableDeclarationSyntax)parent; + if (declaration.Variables.Count != 1) + { + return SymbolInfo.None; + } - return TypeFromLocal((VariableDeclarationSyntax)parent, cancellationToken); + return TypeFromLocal(declaration, cancellationToken); } return this.GetSymbolInfoWorker(expression, SymbolInfoOptions.DefaultOptions, cancellationToken); diff --git a/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt b/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt index b93d886dc3f7c..eb9bebd7f50e1 100644 --- a/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt @@ -125,6 +125,7 @@ Microsoft.CodeAnalysis.CSharp.Syntax.TupleTypeSyntax.WithCloseParenToken(Microso Microsoft.CodeAnalysis.CSharp.Syntax.TupleTypeSyntax.WithElements(Microsoft.CodeAnalysis.SeparatedSyntaxList elements) -> Microsoft.CodeAnalysis.CSharp.Syntax.TupleTypeSyntax Microsoft.CodeAnalysis.CSharp.Syntax.TupleTypeSyntax.WithOpenParenToken(Microsoft.CodeAnalysis.SyntaxToken openParenToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.TupleTypeSyntax Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeclarationSyntax.Deconstruction.get -> Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeconstructionDeclaratorSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeclarationSyntax.IsDeconstructionDeclaration.get -> bool Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeclarationSyntax.WithDeconstruction(Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeconstructionDeclaratorSyntax deconstruction) -> Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeclarationSyntax Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeconstructionDeclaratorSyntax Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeconstructionDeclaratorSyntax.AddVariables(params Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeclarationSyntax[] items) -> Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeconstructionDeclaratorSyntax diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceLocalSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceLocalSymbol.cs index e066619eca943..981c358564d31 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceLocalSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceLocalSymbol.cs @@ -87,17 +87,18 @@ public static SourceLocalSymbol MakeDeconstructionLocal( Symbol containingSymbol, Binder binder, TypeSyntax closestTypeSyntax, - SyntaxToken identifierToken) + SyntaxToken identifierToken, + LocalDeclarationKind kind) { Debug.Assert(closestTypeSyntax != null); if (closestTypeSyntax.IsVar) { - return new PossiblyImplicitlyTypedDeconstructionLocalSymbol(containingSymbol, binder, closestTypeSyntax, identifierToken, LocalDeclarationKind.RegularVariable); + return new PossiblyImplicitlyTypedDeconstructionLocalSymbol(containingSymbol, binder, closestTypeSyntax, identifierToken, kind); } else { - return new SourceLocalSymbol(containingSymbol, binder, RefKind.None, closestTypeSyntax, identifierToken, LocalDeclarationKind.RegularVariable); + return new SourceLocalSymbol(containingSymbol, binder, RefKind.None, closestTypeSyntax, identifierToken, kind); } } @@ -616,7 +617,8 @@ public PossiblyImplicitlyTypedDeconstructionLocalSymbol( #if DEBUG SyntaxNode parent; Debug.Assert(SyntaxFacts.IsDeconstructionIdentifier(identifierToken, out parent)); - Debug.Assert(parent.Parent?.Kind() == SyntaxKind.LocalDeclarationStatement); + Debug.Assert(parent.Parent != null); + Debug.Assert(parent.Parent.Kind() == SyntaxKind.LocalDeclarationStatement || parent.Parent.Kind() == SyntaxKind.ForStatement); #endif } @@ -627,7 +629,7 @@ protected override TypeSymbol InferTypeOfVarVariable(DiagnosticBag diagnostics) bool isDeconstruction = SyntaxFacts.IsDeconstructionIdentifier(IdentifierToken, out topLevelVariableDeclaration); Debug.Assert(isDeconstruction); - Debug.Assert(((VariableDeclarationSyntax)topLevelVariableDeclaration).Deconstruction != null); + Debug.Assert(((VariableDeclarationSyntax)topLevelVariableDeclaration).IsDeconstructionDeclaration); Debug.Assert(((VariableDeclarationSyntax)topLevelVariableDeclaration).Deconstruction.Value != null); var statement = topLevelVariableDeclaration.Parent; @@ -635,14 +637,21 @@ protected override TypeSymbol InferTypeOfVarVariable(DiagnosticBag diagnostics) { case SyntaxKind.LocalDeclarationStatement: this.binder.BindLocalDeclarationStatement((LocalDeclarationStatementSyntax)statement, diagnostics); + break; - TypeSymbol result = this._type; - Debug.Assert((object)result != null); - return result; + case SyntaxKind.ForStatement: + var forStatement = (ForStatementSyntax)statement; + var loopBinder = this.binder.GetBinder(forStatement); + loopBinder.BindDeconstructionDeclaration(forStatement.Declaration, forStatement.Declaration, diagnostics); + break; default: throw ExceptionUtilities.UnexpectedValue(statement.Kind()); } + + TypeSymbol result = this._type; + Debug.Assert((object)result != null); + return result; } } } diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxFacts.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxFacts.cs index c0aa749c7ffb7..c0d72099fb079 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxFacts.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxFacts.cs @@ -434,7 +434,7 @@ private static bool IsDeconstruction(VariableDeclarationSyntax declaration, out } } - return ((VariableDeclarationSyntax)parent).Deconstruction != null; + return ((VariableDeclarationSyntax)parent).IsDeconstructionDeclaration; } } } \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/Syntax/VariableDeclarationSyntax.cs b/src/Compilers/CSharp/Portable/Syntax/VariableDeclarationSyntax.cs index 1a395ec26b382..8985826debfde 100644 --- a/src/Compilers/CSharp/Portable/Syntax/VariableDeclarationSyntax.cs +++ b/src/Compilers/CSharp/Portable/Syntax/VariableDeclarationSyntax.cs @@ -8,5 +8,7 @@ public VariableDeclarationSyntax Update(TypeSyntax type, SeparatedSyntaxList Deconstruction != null; } } diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenDeconstructTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenDeconstructTests.cs index ab238a125232d..e2b52717ec9c1 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenDeconstructTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenDeconstructTests.cs @@ -80,7 +80,7 @@ public void Deconstruct(out int a, out string b) } "; - var comp = CompileAndVerify(source, expectedOutput: "1 hello", parseOptions: TestOptions.Regular); + var comp = CompileAndVerify(source, expectedOutput: "1 hello"); comp.VerifyDiagnostics(); comp.VerifyIL("C.Main", @" { @@ -120,7 +120,7 @@ static void Main() } } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular); + var comp = CreateCompilationWithMscorlib(source); comp.VerifyDiagnostics( // (8,18): error CS1061: 'C' does not contain a definition for 'Deconstruct' and no extension method 'Deconstruct' accepting a first argument of type 'C' could be found (are you missing a using directive or an assembly reference?) // (x, y) = new C(); @@ -157,7 +157,7 @@ public void Deconstruct(out int a) } }"; - var comp = CompileAndVerify(source, expectedOutput: "1 hello", parseOptions: TestOptions.Regular); + var comp = CompileAndVerify(source, expectedOutput: "1 hello"); comp.VerifyDiagnostics(); } @@ -178,7 +178,7 @@ public void Deconstruct(out int a) // too few arguments a = 1; } }"; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular); + var comp = CreateCompilationWithMscorlib(source); comp.VerifyDiagnostics( // (8,18): error CS1501: No overload for method 'Deconstruct' takes 2 arguments // (x, y) = new C(); @@ -205,7 +205,7 @@ public void Deconstruct(out int a, out int b, out int c) // too many arguments a = b = c = 1; } }"; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular); + var comp = CreateCompilationWithMscorlib(source); comp.VerifyDiagnostics( // (7,18): error CS7036: There is no argument given that corresponds to the required formal parameter 'c' of 'C.Deconstruct(out int, out int, out int)' // (x, y) = new C(); @@ -231,7 +231,7 @@ static void Main() public void Deconstruct() { } } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular); + var comp = CreateCompilationWithMscorlib(source); comp.VerifyDiagnostics( // (8,12): error CS1061: 'long' does not contain a definition for 'f' and no extension method 'f' accepting a first argument of type 'long' could be found (are you missing a using directive or an assembly reference?) // (x.f, y.g) = new C(); @@ -263,7 +263,7 @@ static void Main() public void Deconstruct(out int x, int y) { x = 1; } } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular); + var comp = CreateCompilationWithMscorlib(source); comp.VerifyDiagnostics( // (8,9): error CS1615: Argument 2 may not be passed with the 'out' keyword // (x, y) = new C(); @@ -289,7 +289,7 @@ static void Main() public void Deconstruct(ref int x, out int y) { x = 1; y = 2; } } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular); + var comp = CreateCompilationWithMscorlib(source); comp.VerifyDiagnostics( // (8,9): error CS1620: Argument 1 must be passed with the 'ref' keyword // (x, y) = new C(); @@ -324,7 +324,7 @@ public int Deconstruct(out int a, out string b) } "; - var comp = CompileAndVerify(source, expectedOutput: "1 hello", parseOptions: TestOptions.Regular); + var comp = CompileAndVerify(source, expectedOutput: "1 hello"); comp.VerifyDiagnostics(); } @@ -348,7 +348,7 @@ public void Deconstruct(out int a, out int b) } } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular); + var comp = CreateCompilationWithMscorlib(source); comp.VerifyDiagnostics(); } @@ -393,7 +393,7 @@ class D2 Conversion2 setY "; - var comp = CompileAndVerify(source, expectedOutput: expected, parseOptions: TestOptions.Regular); + var comp = CompileAndVerify(source, expectedOutput: expected); comp.VerifyDiagnostics(); } @@ -426,7 +426,7 @@ public void Deconstruct(out int a, out string b, out string c) } "; - var comp = CompileAndVerify(source, expectedOutput: "1 hello world", additionalRefs: new[] { SystemCoreRef }, parseOptions: TestOptions.Regular); + var comp = CompileAndVerify(source, expectedOutput: "1 hello world", additionalRefs: new[] { SystemCoreRef }); comp.VerifyDiagnostics(); } @@ -454,7 +454,7 @@ public void Deconstruct(out int a, out dynamic b) } "; - var comp = CompileAndVerify(source, expectedOutput: "1 hello", additionalRefs: new[] { SystemCoreRef, CSharpRef }, parseOptions: TestOptions.Regular); + var comp = CompileAndVerify(source, expectedOutput: "1 hello", additionalRefs: new[] { SystemCoreRef, CSharpRef }); comp.VerifyDiagnostics(); } @@ -493,7 +493,7 @@ void IDeconstructable.Deconstruct(out int a, out string b) } "; - var comp = CompileAndVerify(source, expectedOutput: "initial modified 1 hello", additionalRefs: new[] { SystemCoreRef, CSharpRef }, parseOptions: TestOptions.Regular); + var comp = CompileAndVerify(source, expectedOutput: "initial modified 1 hello", additionalRefs: new[] { SystemCoreRef, CSharpRef }); comp.VerifyDiagnostics(); } @@ -521,7 +521,7 @@ void Deconstruct(out int a, out string b) } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular); + var comp = CreateCompilationWithMscorlib(source); comp.VerifyDiagnostics( // (10,27): error CS1503: Argument 1: cannot convert from 'out long' to 'out int' // c.Deconstruct(out x, out y); // error @@ -552,7 +552,7 @@ public void Deconstruct(out int a, out string b, int c = 42) // not a Deconstruc } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular); + var comp = CreateCompilationWithMscorlib(source); comp.VerifyDiagnostics( // (9,18): error CS8206: No Deconstruct instance or extension method was found for type 'C', with 2 out parameters. // (x, y) = new C(); @@ -587,7 +587,7 @@ public void Deconstruct(out int a, out string b, int c = 42) // not a Deconstruc } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular); + var comp = CreateCompilationWithMscorlib(source); comp.VerifyDiagnostics( // (13,18): error CS8206: No Deconstruct instance or extension method was found for type 'C', with 2 out parameters. // (x, y) = new C(); @@ -618,7 +618,7 @@ public void Deconstruct(out int a, out string b, params int[] c) // not a Decons } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular); + var comp = CreateCompilationWithMscorlib(source); comp.VerifyDiagnostics( // (9,18): error CS8206: No Deconstruct instance or extension method was found for type 'C', with 2 out parameters. // (x, y) = new C(); @@ -655,7 +655,7 @@ public void Deconstruct(out int a, out string b) } "; - var comp = CompileAndVerify(source, expectedOutput: "2 hello", parseOptions: TestOptions.Regular); + var comp = CompileAndVerify(source, expectedOutput: "2 hello"); comp.VerifyDiagnostics(); } @@ -681,7 +681,7 @@ public void Deconstruct(out int a, out string b, __arglist) // not a Deconstruct } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular); + var comp = CreateCompilationWithMscorlib(source); comp.VerifyDiagnostics( // (9,18): error CS7036: There is no argument given that corresponds to the required formal parameter '__arglist' of 'C.Deconstruct(out int, out string, __arglist)' // (x, y) = new C(); @@ -721,7 +721,7 @@ public void Deconstruct(out int a, out string b, __arglist) // not a Deconstruct } "; - var comp = CompileAndVerify(source, expectedOutput: "1 hello", additionalRefs: new[] { SystemCoreRef, CSharpRef }, parseOptions: TestOptions.Regular); + var comp = CompileAndVerify(source, expectedOutput: "1 hello", additionalRefs: new[] { SystemCoreRef, CSharpRef }); comp.VerifyDiagnostics(); } @@ -745,7 +745,7 @@ static void Main() } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular); + var comp = CreateCompilationWithMscorlib(source); comp.VerifyDiagnostics( // (11,18): error CS8206: No Deconstruct instance or extension method was found for type 'C', with 2 out parameters. // (x, y) = new C() { Deconstruct = DeconstructMethod }; @@ -775,7 +775,7 @@ static void Main() } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular); + var comp = CreateCompilationWithMscorlib(source); comp.VerifyDiagnostics( // (16,17): error CS0102: The type 'C' already contains a definition for 'Deconstruct' // public void Deconstruct(out int a, out int b) { a = 1; b = 2; } @@ -816,7 +816,7 @@ public static void DeconstructMethod(out int a, out int b) } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular); + var comp = CreateCompilationWithMscorlib(source); comp.VerifyDiagnostics( // (14,18): error CS8206: No Deconstruct instance or extension method was found for type 'C', with 2 out parameters. // (x, y) = c; @@ -855,7 +855,7 @@ public void Deconstruct(out int a, out string b, out string c) } "; - var comp = CompileAndVerify(source, expectedOutput: "1 hello world", additionalRefs: new[] { SystemCoreRef }, parseOptions: TestOptions.Regular); + var comp = CompileAndVerify(source, expectedOutput: "1 hello world", additionalRefs: new[] { SystemCoreRef }); comp.VerifyDiagnostics(); } @@ -886,7 +886,7 @@ public void Deconstruct(out int x, out byte y) } "; - var comp = CompileAndVerify(source, expectedOutput: "2 3", additionalRefs: new[] { SystemCoreRef }, parseOptions: TestOptions.Regular); + var comp = CompileAndVerify(source, expectedOutput: "2 3", additionalRefs: new[] { SystemCoreRef }); comp.VerifyDiagnostics(); } @@ -909,7 +909,7 @@ public void Deconstruct(out int a, out int b) } } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular); + var comp = CreateCompilationWithMscorlib(source); comp.VerifyDiagnostics( // (8,9): error CS0266: Cannot implicitly convert type 'int' to 'byte'. An explicit conversion exists (are you missing a cast?) // (x, y) = new C(); @@ -939,7 +939,7 @@ public void Deconstruct(out int a, out int b) } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular); + var comp = CreateCompilationWithMscorlib(source); comp.VerifyDiagnostics( // (7,38): error CS0023: Operator '.' cannot be applied to operand of type 'void' // var type = ((x, y) = new C()).GetType(); @@ -960,7 +960,7 @@ static void Main() } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular); + var comp = CreateCompilationWithMscorlib(source); comp.VerifyDiagnostics( // (6,9): error CS0201: Only assignment, call, increment, decrement, and new object expressions can be used as a statement // (a) => a; @@ -981,7 +981,7 @@ static void Main() } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular); + var comp = CreateCompilationWithMscorlib(source); comp.VerifyDiagnostics( // (6,9): error CS0201: Only assignment, call, increment, decrement, and new object expressions can be used as a statement // (a, b) => { }; @@ -1003,7 +1003,7 @@ static void Main() } "; - var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, parseOptions: TestOptions.Regular); + var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( // (6,24): error CS1525: Invalid expression term '.' // ((int, string)).ToString(); @@ -1052,8 +1052,7 @@ Final i is 43 ); } - [Fact] - [CompilerTrait(CompilerFeature.RefLocalsReturns)] + [Fact, CompilerTrait(CompilerFeature.RefLocalsReturns)] public void RefReturningProperty() { string source = @" @@ -1095,8 +1094,8 @@ Final i is 43 comp.VerifyDiagnostics(); } - [Fact(Skip = "PROTOTYPE(tuples)")] - [CompilerTrait(CompilerFeature.RefLocalsReturns)] + [Fact, CompilerTrait(CompilerFeature.RefLocalsReturns)] + [WorkItem(12283, "https://github.com/dotnet/roslyn/issues/12283")] public void RefReturningMethod2() { string source = @" @@ -1107,11 +1106,12 @@ class C static void Main() { (M(), M()) = new C(); + System.Console.Write(i); } static ref int M() { - System.Console.WriteLine(""M""); + System.Console.Write(""M ""); return ref i; } @@ -1123,13 +1123,12 @@ void Deconstruct(out int i, out int j) } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular.WithRefsFeature()); - comp.VerifyDiagnostics(); - - // This error is wrong - // (4,16): warning CS0649: Field 'C.i' is never assigned to, and will always have its default value 0 - // static int i; - //Diagnostic(ErrorCode.WRN_UnassignedInternalField, "i").WithArguments("C.i", "0").WithLocation(4, 16) + var comp = CompileAndVerify(source, expectedOutput: "M M 43", parseOptions: TestOptions.Regular.WithRefsFeature()); + comp.VerifyDiagnostics( + // (4,16): warning CS0649: Field 'C.i' is never assigned to, and will always have its default value 0 + // static int i; + Diagnostic(ErrorCode.WRN_UnassignedInternalField, "i").WithArguments("C.i", "0").WithLocation(4, 16) + ); } [Fact] @@ -1198,7 +1197,7 @@ static class D } "; - var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef, SystemCoreRef }, parseOptions: TestOptions.Regular); + var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef, SystemCoreRef }); comp.VerifyDiagnostics( // (7,18): error CS0165: Use of unassigned local variable 'x' // (x, x) = x; @@ -1328,7 +1327,7 @@ static void Main() } "; - var comp = CompileAndVerify(source, expectedOutput: "1 hello", additionalRefs: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, parseOptions: TestOptions.Regular); + var comp = CompileAndVerify(source, expectedOutput: "1 hello", additionalRefs: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics(); } @@ -1353,7 +1352,7 @@ static System.ValueTuple M() } } "; - var comp = CompileAndVerify(source, expectedOutput: "1 hello", additionalRefs: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, parseOptions: TestOptions.Regular); + var comp = CompileAndVerify(source, expectedOutput: "1 hello", additionalRefs: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics(); } @@ -1374,7 +1373,7 @@ static void Main() } "; - var comp = CompileAndVerify(source, expectedOutput: "4 2", additionalRefs: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, parseOptions: TestOptions.Regular); + var comp = CompileAndVerify(source, expectedOutput: "4 2", additionalRefs: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics(); comp.VerifyIL("C.Main", @" { @@ -1464,7 +1463,7 @@ static void Main() } "; - var comp = CompileAndVerify(source, expectedOutput: "9 10", additionalRefs: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, parseOptions: TestOptions.Regular); + var comp = CompileAndVerify(source, expectedOutput: "9 10", additionalRefs: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics(); } @@ -1485,7 +1484,7 @@ static void Main() } "; - var comp = CompileAndVerify(source, expectedOutput: "4 2", additionalRefs: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, parseOptions: TestOptions.Regular); + var comp = CompileAndVerify(source, expectedOutput: "4 2", additionalRefs: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics(); } @@ -1506,7 +1505,7 @@ static void Main() } "; - var comp = CompileAndVerify(source, expectedOutput: "hello", additionalRefs: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, parseOptions: TestOptions.Regular); + var comp = CompileAndVerify(source, expectedOutput: "hello", additionalRefs: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics(); comp.VerifyIL("C.Main", @" { @@ -1549,7 +1548,7 @@ static void Main() } } "; - var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, parseOptions: TestOptions.Regular); + var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( // (9,9): error CS0266: Cannot implicitly convert type 'int' to 'byte'. An explicit conversion exists (are you missing a cast?) // (x, y) = (1, 2); @@ -1585,7 +1584,7 @@ public void Deconstruct(out int a, out string b) string expected = @"setX 1 hello"; - var comp = CompileAndVerify(source, expectedOutput: expected, additionalRefs: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, parseOptions: TestOptions.Regular); + var comp = CompileAndVerify(source, expectedOutput: expected, additionalRefs: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics(); } @@ -1608,7 +1607,7 @@ static void Main() string expected = @"setX 1 hello"; - var comp = CompileAndVerify(source, expectedOutput: expected, additionalRefs: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, parseOptions: TestOptions.Regular); + var comp = CompileAndVerify(source, expectedOutput: expected, additionalRefs: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics(); } @@ -1634,7 +1633,7 @@ static void Swap() } "; - var comp = CompileAndVerify(source, expectedOutput: "4 2", additionalRefs: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, parseOptions: TestOptions.Regular); + var comp = CompileAndVerify(source, expectedOutput: "4 2", additionalRefs: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics(); comp.VerifyIL("C.Swap", @" { @@ -1683,7 +1682,7 @@ static void Main() } "; - var comp = CreateCompilationWithMscorlib(source, assemblyName: "comp", parseOptions: TestOptions.Regular); + var comp = CreateCompilationWithMscorlib(source, assemblyName: "comp"); comp.VerifyDiagnostics(); comp.VerifyEmitDiagnostics( // (22,9): error CS8205: Member 'Item2' was not found on type 'ValueTuple' from assembly 'comp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. @@ -1709,7 +1708,7 @@ static void Main() } "; - var comp = CompileAndVerify(source, expectedOutput: "(1, 1) 2", additionalRefs: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, parseOptions: TestOptions.Regular); + var comp = CompileAndVerify(source, expectedOutput: "(1, 1) 2", additionalRefs: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics(); } @@ -1784,7 +1783,7 @@ static void Main() } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular); + var comp = CreateCompilationWithMscorlib(source); comp.VerifyDiagnostics( // (12,18): error CS0121: The call is ambiguous between the following methods or properties: 'Base.Deconstruct(out int, out int)' and 'Base.Deconstruct(out long, out long)' // (x, y) = new C(); @@ -1855,7 +1854,7 @@ static void Main() } "; - var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef, SystemCoreRef, CSharpRef }, parseOptions: TestOptions.Regular); + var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef, SystemCoreRef, CSharpRef }); comp.VerifyDiagnostics( // (7,18): error CS8206: No Deconstruct instance or extension method was found for type 'C', with 2 out parameters. // (x, y) = new C(); @@ -1879,7 +1878,7 @@ static void Main() } "; - var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, parseOptions: TestOptions.Regular); + var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( // (7,18): error CS1955: Non-invocable member 'C.Deconstruct' cannot be used like a method. // (x, y) = new C(); @@ -1965,7 +1964,7 @@ public static Tuple CreateLongRef(this C1 value, out int a, out T b) } "; - var comp = CompileAndVerify(source, expectedOutput: "Deconstructed", additionalRefs: new[] { SystemCoreRef }, parseOptions: TestOptions.Regular); + var comp = CompileAndVerify(source, expectedOutput: "Deconstructed", additionalRefs: new[] { SystemCoreRef }); comp.VerifyDiagnostics(); } @@ -2054,7 +2053,7 @@ static void Main() public void Deconstruct(out int a, out string b) { a = 1; b = ""hello""; } } "; - var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, parseOptions: TestOptions.Regular); + var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( // (10,18): error CS8212: Cannot deconstruct dynamic objects. // (x, y) = c; @@ -2081,7 +2080,7 @@ class C1 protected void Deconstruct(out int a, out string b) { a = 1; b = ""hello""; } } "; - var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, parseOptions: TestOptions.Regular); + var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( // (9,18): error CS0122: 'C1.Deconstruct(out int, out string)' is inaccessible due to its protection level // (x, y) = new C1(); @@ -2120,7 +2119,7 @@ static void Main() var libComp = CreateCompilationWithMscorlib(new string[] { libSource }, references: new[] { libMissingRef }, parseOptions: TestOptions.Regular).VerifyDiagnostics(); var libRef = libComp.EmitToImageReference(); - var comp = CreateCompilationWithMscorlib(new string[] { source }, references: new[] { libRef }, parseOptions: TestOptions.Regular); + var comp = CreateCompilationWithMscorlib(new string[] { source }, references: new[] { libRef }); comp.VerifyDiagnostics( // (7,18): error CS0012: The type 'Missing' is defined in an assembly that is not referenced. You must add a reference to assembly 'libMissingComp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // (x, y) = new C(); @@ -2147,7 +2146,7 @@ static void Main() public static void Deconstruct(out int a, out string b) { a = 1; b = ""hello""; } } "; - var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, parseOptions: TestOptions.Regular); + var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( // (9,18): error CS0176: Member 'C.Deconstruct(out int, out string)' cannot be accessed with an instance reference; qualify it with a type name instead // (x, y) = new C(); @@ -2180,7 +2179,7 @@ public void Deconstruct(out int a, out int b) } } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular); + var comp = CreateCompilationWithMscorlib(source); comp.VerifyDiagnostics( // (8,27): error CS0023: Operator '.' cannot be applied to operand of type 'void' // ((x, y) = new C()).ToString(); @@ -2207,7 +2206,7 @@ static void Main() } } "; - var comp = CompileAndVerify(source, expectedOutput: "1 a b", additionalRefs: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, parseOptions: TestOptions.Regular); + var comp = CompileAndVerify(source, expectedOutput: "1 a b", additionalRefs: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics(); } @@ -2226,7 +2225,7 @@ static void Main() } } "; - var comp = CompileAndVerify(source, expectedOutput: "nothing", additionalRefs: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, parseOptions: TestOptions.Regular); + var comp = CompileAndVerify(source, expectedOutput: "nothing", additionalRefs: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics(); } @@ -2245,7 +2244,7 @@ static void Main() } } "; - var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, parseOptions: TestOptions.Regular); + var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( // (8,24): error CS0037: Cannot convert null to 'int' because it is a non-nullable value type // (x, (y, z)) = (null, (null, null)); @@ -2291,7 +2290,7 @@ public void Deconstruct(out string item1, out string item2) } } "; - var comp = CompileAndVerify(source, expectedOutput: "1 a b", additionalRefs: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, parseOptions: TestOptions.Regular); + var comp = CompileAndVerify(source, expectedOutput: "1 a b", additionalRefs: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics(); } @@ -2318,7 +2317,7 @@ public void Deconstruct(out int item1, out int item2) } } "; - var comp = CompileAndVerify(source, expectedOutput: "1 2 3", additionalRefs: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, parseOptions: TestOptions.Regular); + var comp = CompileAndVerify(source, expectedOutput: "1 2 3", additionalRefs: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics(); } @@ -2346,7 +2345,7 @@ public void Deconstruct(out int item1, out (string, string) item2) } } "; - var comp = CompileAndVerify(source, expectedOutput: "1 a b", additionalRefs: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, parseOptions: TestOptions.Regular); + var comp = CompileAndVerify(source, expectedOutput: "1 a b", additionalRefs: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics(); } @@ -2405,7 +2404,7 @@ class D3 Conversion3 setZ "; - var comp = CompileAndVerify(source, expectedOutput: expected, parseOptions: TestOptions.Regular); + var comp = CompileAndVerify(source, expectedOutput: expected); comp.VerifyDiagnostics(); } @@ -2453,7 +2452,7 @@ Converting 6 setX6 6 Converting 7 setX7 7"; - var comp = CompileAndVerify(source, expectedOutput: expected, parseOptions: TestOptions.Regular); + var comp = CompileAndVerify(source, expectedOutput: expected); comp.VerifyDiagnostics(); } @@ -2482,7 +2481,7 @@ public void Deconstruct(out int a, out string b) } "; - var comp = CompileAndVerify(source, expectedOutput: "1 hello", parseOptions: TestOptions.Regular); + var comp = CompileAndVerify(source, expectedOutput: "1 hello"); comp.VerifyDiagnostics(); } @@ -2516,7 +2515,7 @@ public void Deconstruct(out int a, out string b) } "; // PROTOTYPE(tuples) we expect "2 hello" instead, which means the evaluation order is wrong - var comp = CompileAndVerify(source, expectedOutput: "1 hello", parseOptions: TestOptions.Regular); + var comp = CompileAndVerify(source, expectedOutput: "1 hello"); comp.VerifyDiagnostics(); } @@ -2539,7 +2538,7 @@ public static (int, int) MakePair() } } "; - var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, parseOptions: TestOptions.Regular); + var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( // (8,9): error CS8211: Cannot deconstruct a tuple of '2' elements into '3' variables. // (x, y, z) = MakePair(); @@ -2562,7 +2561,7 @@ static void Main() } " + commonSource; - var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, parseOptions: TestOptions.Regular); + var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( // (8,9): error CS8211: Cannot deconstruct a tuple of '2' elements into '3' variables. // (x, (y, z, w)) = Pair.Create(42, (43, 44)); @@ -2570,7 +2569,7 @@ static void Main() ); } - [Fact(Skip = "PROTOTYPE(tuples)")] + [Fact] public void DeconstructionTooFewElements() { string source = @" @@ -2578,14 +2577,22 @@ class C { static void Main() { - for ((var (x, y)) = new C(); ;) { } + for ((var (x, y)) = Pair.Create(1, 2); ;) { } } } " + commonSource; - var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, parseOptions: TestOptions.Regular); + var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( - // expect ERR_DeconstructTooFewElements + // (6,14): error CS8213: Deconstruction must contain at least two variables. + // for ((var (x, y)) = Pair.Create(1, 2); ;) { } + Diagnostic(ErrorCode.ERR_DeconstructTooFewElements, "(var (x, y)) = Pair.Create(1, 2)").WithLocation(6, 14), + // (6,29): error CS7036: There is no argument given that corresponds to the required formal parameter 'item2' of 'Pair.Deconstruct(out int, out int)' + // for ((var (x, y)) = Pair.Create(1, 2); ;) { } + Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "Pair.Create(1, 2)").WithArguments("item2", "Pair.Deconstruct(out int, out int)").WithLocation(6, 29), + // (6,29): error CS8206: No Deconstruct instance or extension method was found for type 'Pair', with 1 out parameters. + // for ((var (x, y)) = Pair.Create(1, 2); ;) { } + Diagnostic(ErrorCode.ERR_MissingDeconstruct, "Pair.Create(1, 2)").WithArguments("Pair", "1").WithLocation(6, 29) ); } @@ -2631,7 +2638,7 @@ static void Main() } "; - var comp = CompileAndVerify(source, additionalRefs: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, expectedOutput: "1 hello", parseOptions: TestOptions.Regular); + var comp = CompileAndVerify(source, additionalRefs: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, expectedOutput: "1 hello"); comp.VerifyDiagnostics(); } @@ -2724,7 +2731,7 @@ static void Main() } "; - var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, parseOptions: TestOptions.Regular); + var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( // (6,18): error CS0128: A local variable named 'x1' is already defined in this scope // var (x1, x1) = (1, 2); @@ -2747,7 +2754,7 @@ static void Main() } "; - var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, parseOptions: TestOptions.Regular); + var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( // (7,14): error CS0128: A local variable named 'x1' is already defined in this scope // var (x1, x2) = (1, 2); @@ -2770,7 +2777,7 @@ static void Main() } "; - var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, parseOptions: TestOptions.Regular); + var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( // (7,9): error CS0103: The name 'var' does not exist in the current context // var (x1, x2); @@ -2794,7 +2801,7 @@ static void Main() } "; - var comp = CompileAndVerify(source, expectedOutput: "var", additionalRefs: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, parseOptions: TestOptions.Regular); + var comp = CompileAndVerify(source, expectedOutput: "var", additionalRefs: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics(); } @@ -2811,7 +2818,7 @@ static void Main() } "; - var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, parseOptions: TestOptions.Regular); + var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( // (6,28): error CS1001: Identifier expected // (int x1, string x2); @@ -2833,7 +2840,7 @@ static void Main() } "; - var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, parseOptions: TestOptions.Regular); + var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( // (6,30): error CS0165: Use of unassigned local variable 'x1' // (int x1, int x2) = M(x1); @@ -2855,7 +2862,7 @@ static void M(int a) { } } "; - var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, parseOptions: TestOptions.Regular); + var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( // (6,28): error CS1061: 'void' does not contain a definition for 'Deconstruct' and no extension method 'Deconstruct' accepting a first argument of type 'void' could be found (are you missing a using directive or an assembly reference?) // (int x1, int x2) = M(x1); @@ -2883,7 +2890,7 @@ static void Main() } "; - var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, parseOptions: TestOptions.Regular); + var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( // (6,34): error CS0841: Cannot use local variable 'x1' before it is declared // System.Console.WriteLine(x1); @@ -2903,7 +2910,7 @@ static void Main() } } "; - var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, parseOptions: TestOptions.Regular); + var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( // (6,28): error CS8210: Deconstruct assignment requires an expression with a type on the right-hand-side. // (int x1, int x2) = null; @@ -2923,7 +2930,7 @@ static void Main() } } "; - var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, parseOptions: TestOptions.Regular); + var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( // (6,24): error CS8210: Deconstruct assignment requires an expression with a type on the right-hand-side. // var (x1, x2) = null; @@ -2944,7 +2951,7 @@ static void Main() } "; // crash - var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, parseOptions: TestOptions.Regular); + var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( ); } @@ -2963,7 +2970,7 @@ static void Main() } "; // crash - var comp = CompileAndVerify(source, expectedOutput: "1 2 ", parseOptions: TestOptions.Regular); + var comp = CompileAndVerify(source, expectedOutput: "1 2 "); comp.VerifyDiagnostics(); } @@ -3011,11 +3018,21 @@ static void Main() } private static void VerifyModelForDeconstructionLocal(SemanticModel model, VariableDeclarationSyntax decl, params IdentifierNameSyntax[] references) + { + VerifyModelForDeconstruction(model, decl, LocalDeclarationKind.RegularVariable, references); + } + + private static void VerifyModelForDeconstructionFor(SemanticModel model, VariableDeclarationSyntax decl, params IdentifierNameSyntax[] references) + { + VerifyModelForDeconstruction(model, decl, LocalDeclarationKind.ForInitializerVariable, references); + } + + private static void VerifyModelForDeconstruction(SemanticModel model, VariableDeclarationSyntax decl, LocalDeclarationKind kind, params IdentifierNameSyntax[] references) { var variableDeclaratorSyntax = decl.Variables.Single(); var symbol = model.GetDeclaredSymbol(variableDeclaratorSyntax); Assert.Equal(variableDeclaratorSyntax.Identifier.ValueText, symbol.Name); - Assert.Equal(LocalDeclarationKind.RegularVariable, ((LocalSymbol)symbol).DeclarationKind); + Assert.Equal(kind, ((LocalSymbol)symbol).DeclarationKind); Assert.Same(symbol, model.GetDeclaredSymbol((SyntaxNode)variableDeclaratorSyntax)); Assert.Same(symbol, model.LookupSymbols(decl.SpanStart, name: variableDeclaratorSyntax.Identifier.ValueText).Single()); Assert.True(model.LookupNames(decl.SpanStart).Contains(variableDeclaratorSyntax.Identifier.ValueText)); @@ -3053,6 +3070,13 @@ private static IdentifierNameSyntax GetReference(SyntaxTree tree, string name) return GetReferences(tree, name).Single(); } + private static IdentifierNameSyntax[] GetReferences(SyntaxTree tree, string name, int count) + { + var nameRef = GetReferences(tree, name).ToArray(); + Assert.Equal(count, nameRef.Length); + return nameRef; + } + private static IEnumerable GetReferences(SyntaxTree tree, string name) { return tree.GetRoot().DescendantNodes().OfType().Where(id => id.Identifier.ValueText == name); @@ -3091,9 +3115,11 @@ class var var x2Ref = GetReference(tree, "x2"); VerifyModelForDeconstructionLocal(model, x2, x2Ref); + // extra checks on x1 Assert.Equal(SymbolKind.NamedType, model.GetSymbolInfo(x1.Type).Symbol.Kind); Assert.Equal("var", model.GetSymbolInfo(x1.Type).Symbol.ToDisplayString()); + // extra checks on x2 Assert.Equal(SymbolKind.NamedType, model.GetSymbolInfo(x2.Type).Symbol.Kind); Assert.Equal("int", model.GetSymbolInfo(x2.Type).Symbol.ToDisplayString()); }; @@ -3134,7 +3160,7 @@ class var { } } [Fact] - public void DeclarationWithImplicitType() + public void DeclarationWithImplicitVarType() { string source = @" class C @@ -3170,12 +3196,111 @@ static void Main() var x4 = GetDeconstructionLocal(tree, "x4"); var x4Ref = GetReference(tree, "x4"); VerifyModelForDeconstructionLocal(model, x4, x4Ref); + + // extra checks on x1 + Assert.Equal(SymbolKind.NamedType, model.GetSymbolInfo(x1.Type).Symbol.Kind); + Assert.Equal("int", model.GetSymbolInfo(x1.Type).Symbol.ToDisplayString()); + Assert.Null(model.GetAliasInfo(x1.Type)); + + // extra checks on x3 and x4 + Assert.Null(x3.Type); + Assert.Null(x4.Type); + + var x34Var = (VariableDeclarationSyntax) x3.Parent.Parent; + Assert.Equal("var", x34Var.Type.ToString()); + Assert.Null(model.GetSymbolInfo(x34Var.Type).Symbol); // The var in `var (x3, x4)` has no symbol }; var comp = CompileAndVerify(source, expectedOutput: "1 2 3 4", additionalRefs: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, sourceSymbolValidator: validator); comp.VerifyDiagnostics(); } + [Fact] + public void DeclarationWithAliasedVarType() + { + string source = @" +using var = D; +class C +{ + static void Main() + { + (var x1, int x2) = (new var(), 2); + System.Console.WriteLine(x1 + "" "" + x2); + } +} +class D +{ + public override string ToString() { return ""var""; } +} +"; + + Action validator = (ModuleSymbol module) => + { + var sourceModule = (SourceModuleSymbol)module; + var compilation = sourceModule.DeclaringCompilation; + var tree = compilation.SyntaxTrees.First(); + var model = compilation.GetSemanticModel(tree); + + var x1 = GetDeconstructionLocal(tree, "x1"); + var x1Ref = GetReference(tree, "x1"); + VerifyModelForDeconstructionLocal(model, x1, x1Ref); + + var x2 = GetDeconstructionLocal(tree, "x2"); + var x2Ref = GetReference(tree, "x2"); + VerifyModelForDeconstructionLocal(model, x2, x2Ref); + + // extra checks on x1 + Assert.Equal(SymbolKind.NamedType, model.GetSymbolInfo(x1.Type).Symbol.Kind); + Assert.Equal("D", model.GetSymbolInfo(x1.Type).Symbol.ToDisplayString()); + var x1Alias = model.GetAliasInfo(x1.Type); + Assert.Equal(SymbolKind.NamedType, x1Alias.Target.Kind); + Assert.Equal("D", x1Alias.Target.ToDisplayString()); + + // extra checks on x2 + Assert.Equal(SymbolKind.NamedType, model.GetSymbolInfo(x2.Type).Symbol.Kind); + Assert.Equal("int", model.GetSymbolInfo(x2.Type).Symbol.ToDisplayString()); + Assert.Null(model.GetAliasInfo(x2.Type)); + }; + + var comp = CompileAndVerify(source, expectedOutput: "var 2", additionalRefs: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, sourceSymbolValidator: validator); + comp.VerifyDiagnostics(); + } + + [Fact] + public void DeclarationVarFormWithAliasedVarType() + { + string source = @" +using var = D; +class C +{ + static void Main() + { + var (x3, x4) = (3, 4); + } +} +class D +{ + public override string ToString() { return ""var""; } +} +"; + + var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); + comp.VerifyDiagnostics( + // (7,14): error CS8215: Deconstruction `var (...)` form disallows a specific type for 'var'. + // var (x3, x4) = (3, 4); + Diagnostic(ErrorCode.ERR_DeconstructionVarFormDisallowsSpecificType, "x3").WithLocation(7, 14), + // (7,18): error CS8215: Deconstruction `var (...)` form disallows a specific type for 'var'. + // var (x3, x4) = (3, 4); + Diagnostic(ErrorCode.ERR_DeconstructionVarFormDisallowsSpecificType, "x4").WithLocation(7, 18), + // (7,24): error CS0029: Cannot implicitly convert type 'int' to 'D' + // var (x3, x4) = (3, 4); + Diagnostic(ErrorCode.ERR_NoImplicitConv, "(3, 4)").WithArguments("int", "D").WithLocation(7, 24), + // (7,24): error CS0029: Cannot implicitly convert type 'int' to 'D' + // var (x3, x4) = (3, 4); + Diagnostic(ErrorCode.ERR_NoImplicitConv, "(3, 4)").WithArguments("int", "D").WithLocation(7, 24) + ); + } + [Fact] public void DeclarationWithWrongCardinality() { @@ -3189,7 +3314,7 @@ static void Main() } "; - var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, parseOptions: TestOptions.Regular); + var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( // (6,34): error CS8211: Cannot deconstruct a tuple of '3' elements into '2' variables. // (var (x1, x2), var x3) = (1, 2, 3); @@ -3197,6 +3322,90 @@ static void Main() ); } + [Fact(Skip = "PROTOTYPE(tuples)")] + public void DeclarationWithCircularity1() + { + string source = @" +class C +{ + static void Main() + { + var (x1, x2) = (1, x1); + System.Console.WriteLine(x1 + "" "" + x2); + } +} +"; + + Action validator = (ModuleSymbol module) => + { + var sourceModule = (SourceModuleSymbol)module; + var compilation = sourceModule.DeclaringCompilation; + var tree = compilation.SyntaxTrees.First(); + var model = compilation.GetSemanticModel(tree); + + var x1 = GetDeconstructionLocal(tree, "x1"); + var x1Ref = GetReferences(tree, "x1", 2); + VerifyModelForDeconstructionLocal(model, x1, x1Ref); + + var x2 = GetDeconstructionLocal(tree, "x2"); + var x2Ref = GetReference(tree, "x2"); + VerifyModelForDeconstructionLocal(model, x2, x2Ref); + + // extra checks on x1 + Assert.Equal(SymbolKind.NamedType, model.GetSymbolInfo(x1.Type).Symbol.Kind); + Assert.Equal("int", model.GetSymbolInfo(x1.Type).Symbol.ToDisplayString()); + + // extra checks on x2 + Assert.Equal(SymbolKind.NamedType, model.GetSymbolInfo(x2.Type).Symbol.Kind); + Assert.Equal("int", model.GetSymbolInfo(x2.Type).Symbol.ToDisplayString()); + }; + + var comp = CompileAndVerify(source, expectedOutput: "1 1", additionalRefs: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, sourceSymbolValidator: validator); + comp.VerifyDiagnostics( ); + } + + [Fact(Skip = "PROTOTYPE(tuples)")] + public void DeclarationWithCircularity2() + { + string source = @" +class C +{ + static void Main() + { + var (x1, x2) = (x2, 2); + System.Console.WriteLine(x1 + "" "" + x2); + } +} +"; + + Action validator = (ModuleSymbol module) => + { + var sourceModule = (SourceModuleSymbol)module; + var compilation = sourceModule.DeclaringCompilation; + var tree = compilation.SyntaxTrees.First(); + var model = compilation.GetSemanticModel(tree); + + var x1 = GetDeconstructionLocal(tree, "x1"); + var x1Ref = GetReference(tree, "x1"); + VerifyModelForDeconstructionLocal(model, x1, x1Ref); + + var x2 = GetDeconstructionLocal(tree, "x2"); + var x2Ref = GetReferences(tree, "x2", 2); + VerifyModelForDeconstructionLocal(model, x2, x2Ref); + + // extra checks on x1 + Assert.Equal(SymbolKind.NamedType, model.GetSymbolInfo(x1.Type).Symbol.Kind); + Assert.Equal("int", model.GetSymbolInfo(x1.Type).Symbol.ToDisplayString()); + + // extra checks on x2 + Assert.Equal(SymbolKind.NamedType, model.GetSymbolInfo(x2.Type).Symbol.Kind); + Assert.Equal("int", model.GetSymbolInfo(x2.Type).Symbol.ToDisplayString()); + }; + + var comp = CompileAndVerify(source, expectedOutput: "2 2", additionalRefs: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, sourceSymbolValidator: validator); + comp.VerifyDiagnostics(); + } + [Fact, CompilerTrait(CompilerFeature.RefLocalsReturns)] [WorkItem(12283, "https://github.com/dotnet/roslyn/issues/12283")] public void RefReturningVarInvocation() @@ -3331,5 +3540,161 @@ static void Main() Diagnostic(ErrorCode.ERR_NameNotInContext, "var").WithArguments("var").WithLocation(8, 9) ); } + + [Fact] + public void ForDeclarationWithImplicitVarType() + { + string source = @" +class C +{ + static void Main() + { + for (var (x1, x2) = (1, 2); x1 < 2; (x1, x2) = (x1 + 1, x2 + 1)) + { + System.Console.WriteLine(x1 + "" "" + x2); + } + } +} +"; + + Action validator = (ModuleSymbol module) => + { + var sourceModule = (SourceModuleSymbol)module; + var compilation = sourceModule.DeclaringCompilation; + var tree = compilation.SyntaxTrees.First(); + var model = compilation.GetSemanticModel(tree); + + var x1 = GetDeconstructionLocal(tree, "x1"); + var x1Ref = GetReferences(tree, "x1", 4); + VerifyModelForDeconstructionFor(model, x1, x1Ref); + + var x2 = GetDeconstructionLocal(tree, "x2"); + var x2Ref = GetReferences(tree, "x2", 3); + VerifyModelForDeconstructionFor(model, x2, x2Ref); + + // extra check on var + var x12Var = (VariableDeclarationSyntax)x1.Parent.Parent; + Assert.Equal("var", x12Var.Type.ToString()); + Assert.Null(model.GetSymbolInfo(x12Var.Type).Symbol); // The var in `var (x1, x2)` has no symbol + }; + + var comp = CompileAndVerify(source, expectedOutput: "1 2", additionalRefs: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, sourceSymbolValidator: validator); + comp.VerifyDiagnostics( ); + } + + [Fact] + public void ForDeclarationWithActualVarType() + { + string source = @" +class C +{ + static void Main() + { + for ((int x1, var x2) = (1, new var()); x1 < 2; x1++) + { + System.Console.WriteLine(x1 + "" "" + x2); + } + } +} +class var +{ + public override string ToString() { return ""var""; } +} +"; + + Action validator = (ModuleSymbol module) => + { + var sourceModule = (SourceModuleSymbol)module; + var compilation = sourceModule.DeclaringCompilation; + var tree = compilation.SyntaxTrees.First(); + var model = compilation.GetSemanticModel(tree); + + var x1 = GetDeconstructionLocal(tree, "x1"); + var x1Ref = GetReferences(tree, "x1", 3); + VerifyModelForDeconstructionFor(model, x1, x1Ref); + + var x2 = GetDeconstructionLocal(tree, "x2"); + var x2Ref = GetReference(tree, "x2"); + VerifyModelForDeconstructionFor(model, x2, x2Ref); + + // extra checks on x1 + Assert.Equal(SymbolKind.NamedType, model.GetSymbolInfo(x1.Type).Symbol.Kind); + Assert.Equal("int", model.GetSymbolInfo(x1.Type).Symbol.ToDisplayString()); + + // extra checks on x2 + Assert.Equal(SymbolKind.NamedType, model.GetSymbolInfo(x2.Type).Symbol.Kind); + Assert.Equal("var", model.GetSymbolInfo(x2.Type).Symbol.ToDisplayString()); + }; + + var comp = CompileAndVerify(source, expectedOutput: "1 var", additionalRefs: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, sourceSymbolValidator: validator); + comp.VerifyDiagnostics(); + } + + [Fact] + public void ForDeconstructionWithTypes() + { + string source = @" +class C +{ + static void Main() + { + for ((int x1, var x2) = (1, 2); x1 < 2; x1++) + { + System.Console.WriteLine(x1 + "" "" + x2); + } + } +} +"; + + Action validator = (ModuleSymbol module) => + { + var sourceModule = (SourceModuleSymbol)module; + var compilation = sourceModule.DeclaringCompilation; + var tree = compilation.SyntaxTrees.First(); + var model = compilation.GetSemanticModel(tree); + + var x1 = GetDeconstructionLocal(tree, "x1"); + var x1Ref = GetReferences(tree, "x1", 3); + VerifyModelForDeconstructionFor(model, x1, x1Ref); + + var x2 = GetDeconstructionLocal(tree, "x2"); + var x2Ref = GetReference(tree, "x2"); + VerifyModelForDeconstructionFor(model, x2, x2Ref); + + // extra checks on x1 + Assert.Equal(SymbolKind.NamedType, model.GetSymbolInfo(x1.Type).Symbol.Kind); + Assert.Equal("int", model.GetSymbolInfo(x1.Type).Symbol.ToDisplayString()); + + // extra checks on x2 + Assert.Equal(SymbolKind.NamedType, model.GetSymbolInfo(x2.Type).Symbol.Kind); + Assert.Equal("int", model.GetSymbolInfo(x2.Type).Symbol.ToDisplayString()); + }; + + var comp = CompileAndVerify(source, expectedOutput: "1 2", additionalRefs: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, sourceSymbolValidator: validator); + comp.VerifyDiagnostics(); + } + + [Fact] + public void ForDeconstructionWithExistingVariableName() + { + string source = @" +class C +{ + static void Main() + { + string x = ""hello""; + for (var (x, y) = (1, 2); x < 2; x++) { } + System.Console.Write(x); + } +} +"; + var comp = CreateCompilationWithMscorlib(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); + comp.VerifyDiagnostics( + // (7,19): error CS0136: A local or parameter named 'x' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter + // for (var (x, y) = (1, 2); x < 2; x++) + Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "x").WithArguments("x").WithLocation(7, 19) + ); + } + } -} \ No newline at end of file +} diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTupleTest.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTupleTest.cs index 70987c33b9a71..84824335c1343 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTupleTest.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTupleTest.cs @@ -4357,11 +4357,16 @@ class C var tuple3 = (TypeSymbol)comp.CreateTupleTypeSymbol(ImmutableArray.Create(intType, intType, intType, intType, intType, intType, intType, stringType, stringType), ImmutableArray.Create("Item1", "Item2", "Item3", "Item4", "Item5", "Item6", "Item7", "a", "b")); + var tuple4 = (TypeSymbol)comp.CreateTupleTypeSymbol((INamedTypeSymbol)tuple1.TupleUnderlyingType, ImmutableArray.Create("Item1", "Item2", "Item3", "Item4", "Item5", "Item6", "Item7", "a", "b")); + Assert.True(tuple1.Equals(tuple2)); Assert.True(tuple1.Equals(tuple2, ignoreDynamic: true)); Assert.False(tuple1.Equals(tuple3)); Assert.True(tuple1.Equals(tuple3, ignoreDynamic: true)); + + Assert.False(tuple1.Equals(tuple4)); + Assert.True(tuple1.Equals(tuple4, ignoreDynamic: true)); } [Fact]