Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use default tuple fields in conversion since fields from inferred names are marked not usable in C#7 #21553

Merged
merged 3 commits into from
Aug 19, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,14 +189,7 @@ private ImmutableArray<BoundExpression> AccessTupleFields(BoundExpression expres
var builder = ArrayBuilder<BoundExpression>.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();
Expand Down
Original file line number Diff line number Diff line change
@@ -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
{
Expand Down Expand Up @@ -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);
}
}
}
257 changes: 257 additions & 0 deletions src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenDeconstructTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<T>(System.Func<object, bool, T> 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<T1, T2>
{
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<T1, T2>' 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<T1, T2>", "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<T1, T2>' 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<T1, T2>", "39f5d0e8-2935-4207-a74d-517a8e55af08, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(5, 22));
}
}
}
23 changes: 23 additions & 0 deletions src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTupleTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<object>) items)
{
}
static void Test()
{
var items = new List<object>();
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()
{
Expand Down
Loading