diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Conversion.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Conversion.cs index 6669daccf1e57..d16de2bc65eaa 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Conversion.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Conversion.cs @@ -649,16 +649,8 @@ private BoundExpression RewriteTupleConversion( for (int i = 0; i < numElements; i++) { - var field = srcElementFields[i]; - - DiagnosticInfo useSiteInfo = field.GetUseSiteDiagnostic(); - if ((object)useSiteInfo != null && useSiteInfo.Severity == DiagnosticSeverity.Error) - { - Symbol.ReportUseSiteDiagnostic(useSiteInfo, _diagnostics, syntax.Location); - } - var fieldAccess = MakeTupleFieldAccess(syntax, field, savedTuple, null, LookupResultKind.Empty); + var fieldAccess = MakeTupleFieldAccessAndReportUseSiteDiagnostics(savedTuple, syntax, srcElementFields[i]); var convertedFieldAccess = MakeConversionNode(syntax, fieldAccess, elementConversions[i], destElementTypes[i], @checked, explicitCastInCode); - fieldAccessorsBuilder.Add(convertedFieldAccess); } diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_DeconstructionAssignmentOperator.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_DeconstructionAssignmentOperator.cs index ce99b37b3be55..399d435fc0d57 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_DeconstructionAssignmentOperator.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_DeconstructionAssignmentOperator.cs @@ -189,14 +189,7 @@ private ImmutableArray AccessTupleFields(BoundExpression expres var builder = ArrayBuilder.GetInstance(numElements); for (int i = 0; i < numElements; i++) { - var field = fields[i]; - - DiagnosticInfo useSiteInfo = field.GetUseSiteDiagnostic(); - if ((object)useSiteInfo != null && useSiteInfo.Severity == DiagnosticSeverity.Error) - { - Symbol.ReportUseSiteDiagnostic(useSiteInfo, _diagnostics, expression.Syntax.Location); - } - var fieldAccess = MakeTupleFieldAccess(expression.Syntax, field, tuple, null, LookupResultKind.Empty); + var fieldAccess = MakeTupleFieldAccessAndReportUseSiteDiagnostics(tuple, expression.Syntax, fields[i]); builder.Add(fieldAccess); } return builder.ToImmutableAndFree(); diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Field.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Field.cs index af83455550b77..0a125813109da 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Field.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Field.cs @@ -1,7 +1,6 @@ // 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 System.Diagnostics; namespace Microsoft.CodeAnalysis.CSharp { @@ -92,5 +91,20 @@ private BoundExpression MakeTupleFieldAccess( // make a field access for the most local access return _factory.Field(rewrittenReceiver, underlyingField); } + + private BoundExpression MakeTupleFieldAccessAndReportUseSiteDiagnostics(BoundExpression tuple, SyntaxNode syntax, FieldSymbol field) + { + // Use default field rather than implicitly named fields since + // fields from inferred names are not usable in C# 7.0. + field = field.CorrespondingTupleField ?? field; + + DiagnosticInfo useSiteInfo = field.GetUseSiteDiagnostic(); + if ((object)useSiteInfo != null && useSiteInfo.Severity == DiagnosticSeverity.Error) + { + Symbol.ReportUseSiteDiagnostic(useSiteInfo, _diagnostics, syntax.Location); + } + + return MakeTupleFieldAccess(syntax, field, tuple, null, LookupResultKind.Empty); + } } } diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenDeconstructTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenDeconstructTests.cs index 90614cb23dc55..3e2ed1192740e 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenDeconstructTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenDeconstructTests.cs @@ -7366,5 +7366,262 @@ public static explicit operator (byte, byte)(C c) }"; CompileAndVerify(source, expectedOutput: @"3 4", additionalRefs: s_valueTupleRefs); } + + [Fact, WorkItem(19398, "https://github.com/dotnet/roslyn/issues/19398")] + public void DeconstructionLoweredToNothing() + { + var source = @" +class C +{ + static void M() + { + for (var(_, _) = (1, 2); ; (_, _) = (3, 4)) + { + } + } +}"; + var comp = CreateStandardCompilation(source, parseOptions: TestOptions.Regular7, references: s_valueTupleRefs); + comp.VerifyDiagnostics(); + var verifier = CompileAndVerify(comp); + verifier.VerifyIL("C.M", @" +{ + // Code size 2 (0x2) + .maxstack 0 + IL_0000: br.s IL_0000 +}"); + } + + [Fact, WorkItem(19398, "https://github.com/dotnet/roslyn/issues/19398")] + public void DeconstructionLoweredToNothing2() + { + var source = @" +class C +{ + static void M() + { + (_, _) = (1, 2); + } +}"; + var comp = CreateStandardCompilation(source, parseOptions: TestOptions.Regular7, references: s_valueTupleRefs); + comp.VerifyDiagnostics(); + var verifier = CompileAndVerify(comp); + verifier.VerifyIL("C.M", @" +{ + // Code size 1 (0x1) + .maxstack 0 + IL_0000: ret +}"); + } + + [Fact, WorkItem(19398, "https://github.com/dotnet/roslyn/issues/19398")] + public void DeconstructionLoweredToNothing3() + { + var source = @" +class C +{ + static void Main() + { + foreach (var(_, _) in new[] { (1, 2) }) + { + System.Console.Write(""once""); + } + } +}"; + var comp = CreateStandardCompilation(source, parseOptions: TestOptions.Regular7, references: s_valueTupleRefs, options: TestOptions.DebugExe); + comp.VerifyDiagnostics(); + CompileAndVerify(comp, expectedOutput: "once"); + } + + [WorkItem(21028, "https://github.com/dotnet/roslyn/issues/21028")] + [Fact] + public void InferredName() + { + var source = +@"class C +{ + static void Main() + { + int x = 0, y = 1; + var t = (x, y); + var (a, b) = t; + } +}"; + // C# 7.0 + var comp = CreateStandardCompilation( + source, + parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7), + references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); + comp.VerifyEmitDiagnostics(); + // C# 7.1 + comp = CreateStandardCompilation( + source, + parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1), + references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); + comp.VerifyEmitDiagnostics(); + } + + [WorkItem(21028, "https://github.com/dotnet/roslyn/issues/21028")] + [Fact] + public void InferredName_ConditionalOperator() + { + var source = +@"class C +{ + static void M(int a, int b, bool c) + { + (var x, var y) = c ? (a, default(object)) : (b, null); + (x, y) = c ? (a, default(string)) : (b, default(object)); + } +}"; + // C# 7.0 + var comp = CreateStandardCompilation( + source, + parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7), + references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); + comp.VerifyEmitDiagnostics(); + // C# 7.1 + comp = CreateStandardCompilation( + source, + parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1), + references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); + comp.VerifyEmitDiagnostics(); + } + + [WorkItem(21028, "https://github.com/dotnet/roslyn/issues/21028")] + [Fact] + public void InferredName_ImplicitArray() + { + var source = +@"class C +{ + static void M(int x) + { + int y; + object z; + (y, z) = (new [] { (x, default(object)), (2, 3) })[0]; + } +}"; + // C# 7.0 + var comp = CreateStandardCompilation( + source, + parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7), + references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); + comp.VerifyEmitDiagnostics(); + // C# 7.1 + comp = CreateStandardCompilation( + source, + parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1), + references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); + comp.VerifyEmitDiagnostics(); + } + + [WorkItem(21028, "https://github.com/dotnet/roslyn/issues/21028")] + [Fact] + public void InferredName_Lambda() + { + var source = +@"class C +{ + static T F(System.Func f) + { + return f(null, false); + } + static void M() + { + var (x, y) = F((a, b) => + { + if (b) return (default(object), a); + return (null, null); + }); + } +}"; + // C# 7.0 + var comp = CreateStandardCompilation( + source, + parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7), + references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); + comp.VerifyEmitDiagnostics(); + // C# 7.1 + comp = CreateStandardCompilation( + source, + parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1), + references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); + comp.VerifyEmitDiagnostics(); + } + + [WorkItem(21028, "https://github.com/dotnet/roslyn/issues/21028")] + [Fact] + public void InferredName_ConditionalOperator_LongTuple() + { + var source = +@"class C +{ + static void M(object a, object b, bool c) + { + var (_1, _2, _3, _4, _5, _6, _7, _8, _9, _10) = c ? + (1, 2, 3, 4, 5, 6, 7, a, b, 10) : + (1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + } +}"; + // C# 7.0 + var comp = CreateStandardCompilation( + source, + parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7), + references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); + comp.VerifyEmitDiagnostics(); + // C# 7.1 + comp = CreateStandardCompilation( + source, + parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1), + references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); + comp.VerifyEmitDiagnostics(); + } + + [WorkItem(21028, "https://github.com/dotnet/roslyn/issues/21028")] + [Fact] + public void InferredName_ConditionalOperator_UseSite() + { + var source = +@"class C +{ + static void M(int a, int b, bool c) + { + var (x, y) = c ? ((object)1, a) : (b, 2); + } +} +namespace System +{ + struct ValueTuple + { + public T1 Item1; + private T2 Item2; + public ValueTuple(T1 item1, T2 item2) + { + Item1 = item1; + Item2 = item2; + } + } +}"; + // C# 7.0 + var comp = CreateStandardCompilation( + source, + assemblyName: "39f5d0e8-2935-4207-a74d-517a8e55af08", + parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7), + references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); + comp.VerifyEmitDiagnostics( + // (5,22): error CS8128: Member 'Item2' was not found on type 'ValueTuple' from assembly '39f5d0e8-2935-4207-a74d-517a8e55af08, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. + // var (x, y) = c ? ((object)1, a) : (b, 2); + Diagnostic(ErrorCode.ERR_PredefinedTypeMemberNotFoundInAssembly, "c ? ((object)1, a) : (b, 2)").WithArguments("Item2", "System.ValueTuple", "39f5d0e8-2935-4207-a74d-517a8e55af08, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(5, 22)); + // C# 7.1 + comp = CreateStandardCompilation( + source, + assemblyName: "39f5d0e8-2935-4207-a74d-517a8e55af08", + parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1), + references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); + comp.VerifyEmitDiagnostics( + // (5,22): error CS8128: Member 'Item2' was not found on type 'ValueTuple' from assembly '39f5d0e8-2935-4207-a74d-517a8e55af08, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. + // var (x, y) = c ? ((object)1, a) : (b, 2); + Diagnostic(ErrorCode.ERR_PredefinedTypeMemberNotFoundInAssembly, "c ? ((object)1, a) : (b, 2)").WithArguments("Item2", "System.ValueTuple", "39f5d0e8-2935-4207-a74d-517a8e55af08, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(5, 22)); + } } } diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTupleTest.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTupleTest.cs index 2f1c805366eed..8bef243e3a728 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTupleTest.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTupleTest.cs @@ -3938,6 +3938,29 @@ static class Extension verifier7_1.VerifyDiagnostics(); } + [WorkItem(21518, "https://github.com/dotnet/roslyn/issues/21518")] + [Fact] + public void InferredName_Conversion() + { + var source = +@"using System.Collections.Generic; +class C +{ + static void F((int, IList) items) + { + } + static void Test() + { + var items = new List(); + var group = (1, items); + F(group); + } +}"; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7), + references: new[] { MscorlibRef, ValueTupleRef, SystemRuntimeFacadeRef, SystemCoreRef }); + comp.VerifyEmitDiagnostics(); + } + [Fact] public void LongTupleWithArgumentEvaluation() { diff --git a/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenTuples.vb b/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenTuples.vb index 459b922901c42..d1d6fac2bca2d 100644 --- a/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenTuples.vb +++ b/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenTuples.vb @@ -6277,6 +6277,28 @@ BC37289: Tuple element name 'M' is inferred. Please use language version 15.3 or verifier15_3.VerifyDiagnostics() End Sub + + Public Sub InferredName_Conversion() + Dim source = + +Imports System.Collections.Generic +Class C + Shared Sub F(items As (Integer, IList(Of Object))) + End Sub + Shared Sub Test() + Dim items = New List(Of Object)() + Dim group = (1, items) + F(group) + End Sub +End Class + + + Dim comp = CreateCompilationWithMscorlibAndVBRuntime(source, + additionalRefs:={ValueTupleRef, SystemRuntimeFacadeRef, SystemCoreRef}, + parseOptions:=TestOptions.Regular.WithLanguageVersion(LanguageVersion.VisualBasic15)) + comp.AssertTheseEmitDiagnostics() + End Sub + Public Sub LongTupleWithArgumentEvaluation() @@ -7564,7 +7586,7 @@ BC36625: Lambda expression cannot be converted to 'Integer' because 'Integer' is End Sub - Public Sub TupleInferredLambdStrictOn() + Public Sub TupleInferredLambdaStrictOn() Dim comp = CreateCompilationWithMscorlibAndVBRuntime( @@ -7600,7 +7622,7 @@ BC36642: Option Strict On requires each lambda expression parameter to be declar End Sub - Public Sub TupleInferredLambdStrictOff() + Public Sub TupleInferredLambdaStrictOff() Dim verifier = CompileAndVerify(