提交 d434b0a8 编写于 作者: J Julien Couvreur 提交者: GitHub

Deconstruct should return void and disallow 1-deconstruction (#15922)

上级 908ea747
......@@ -12,3 +12,6 @@ Each entry should include a short description of the break, followed by either a
[#11256](https://github.com/dotnet/roslyn/pull/11256) for when it was discovered, and [#10463](https://github.com/dotnet/roslyn/issues/10463) for the original issue that led to this.
3. Native compiler used to generate warnings (169, 414, 649) on unused/unassigned fields of abstract classes.
Roslyn 1 (VS 2015) didn't produce these warnings. With [#14628](https://github.com/dotnet/roslyn/pull/14628) these warnings should be reported again.
4. In preview and RC releases of VS 2017 and C#7.0, deconstruction was allowed with a Deconstruct method that returned something (non-void return type).
Starting in RC.3, the Deconstruct method is required to return void. This will allow for future versions of C# to attach special semantics to the return value.
See issue [#15634](https://github.com/dotnet/roslyn/issues/15634) and PR [#15922](https://github.com/dotnet/roslyn/pull/15922) for more details.
......@@ -92,7 +92,7 @@ private static void FreeDeconstructionVariables(ArrayBuilder<DeconstructionVaria
boundRHS = FixTupleLiteral(checkedVariables, boundRHS, node, diagnostics);
if ((object)boundRHS.Type == null)
if ((object)boundRHS.Type == null || boundRHS.Type.IsErrorType())
{
// we could still not infer a type for the RHS
FailRemainingInferences(checkedVariables, diagnostics);
......@@ -550,6 +550,13 @@ private static void FlattenDeconstructVariables(ArrayBuilder<DeconstructionVaria
DiagnosticBag diagnostics, out ImmutableArray<BoundDeconstructValuePlaceholder> outPlaceholders)
{
var receiverSyntax = receiver.Syntax;
if (numCheckedVariables < 2)
{
Error(diagnostics, ErrorCode.ERR_DeconstructTooFewElements, receiverSyntax);
outPlaceholders = default(ImmutableArray<BoundDeconstructValuePlaceholder>);
return BadExpression(receiverSyntax, receiver);
}
if (receiver.Type.IsDynamic())
{
......@@ -617,6 +624,11 @@ private static void FlattenDeconstructVariables(ArrayBuilder<DeconstructionVaria
}
}
if (deconstructMethod.ReturnType.GetSpecialTypeSafe() != SpecialType.System_Void)
{
return MissingDeconstruct(receiver, syntax, numCheckedVariables, diagnostics, out outPlaceholders, result);
}
if (outVars.Any(v => (object)v.Placeholder == null))
{
return MissingDeconstruct(receiver, syntax, numCheckedVariables, diagnostics, out outPlaceholders, result);
......
......@@ -6047,7 +6047,7 @@ internal class CSharpResources {
}
/// <summary>
/// Looks up a localized string similar to No Deconstruct instance or extension method was found for type &apos;{0}&apos;, with {1} out parameters..
/// Looks up a localized string similar to No Deconstruct instance or extension method was found for type &apos;{0}&apos;, with {1} out parameters and a void return type..
/// </summary>
internal static string ERR_MissingDeconstruct {
get {
......
......@@ -4871,7 +4871,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<value>tuples</value>
</data>
<data name="ERR_MissingDeconstruct" xml:space="preserve">
<value>No Deconstruct instance or extension method was found for type '{0}', with {1} out parameters.</value>
<value>No Deconstruct instance or extension method was found for type '{0}', with {1} out parameters and a void return type.</value>
</data>
<data name="ERR_DeconstructRequiresExpression" xml:space="preserve">
<value>Deconstruct assignment requires an expression with a type on the right-hand-side.</value>
......
......@@ -216,7 +216,8 @@ public void Deconstruct(out int a)
}
[Fact]
public void DeconstructCanHaveReturnType()
[WorkItem(15634, "https://github.com/dotnet/roslyn/issues/15634")]
public void DeconstructMustReturnVoid()
{
string source = @"
class C
......@@ -225,9 +226,7 @@ static void Main()
{
long x;
string y;
(x, y) = new C();
System.Console.WriteLine(x + "" "" + y);
}
public int Deconstruct(out int a, out string b)
......@@ -238,9 +237,12 @@ public int Deconstruct(out int a, out string b)
}
}
";
var comp = CompileAndVerify(source, expectedOutput: "1 hello", additionalRefs: s_valueTupleRefs);
comp.VerifyDiagnostics();
var comp = CreateCompilationWithMscorlib(source, references: s_valueTupleRefs);
comp.VerifyDiagnostics(
// (8,18): error CS8129: No Deconstruct instance or extension method was found for type 'C', with 2 out parameters and a void return type.
// (x, y) = new C();
Diagnostic(ErrorCode.ERR_MissingDeconstruct, "new C()").WithArguments("C", "2").WithLocation(8, 18)
);
}
[Fact]
......@@ -5819,6 +5821,82 @@ static void Main()
VerifyModelForDeconstructionLocal(model, x2, x2Ref);
}
[Fact]
[WorkItem(15893, "https://github.com/dotnet/roslyn/issues/15893")]
public void DeconstructionOfOnlyOneElement()
{
string source = @"
class C
{
public int a;
public void Deconstruct(out int b)
{
b = a;
}
static void Main()
{
var p = new C() { a = 10 };
var (p2) = p;
}
}
";
var compilation = CreateCompilationWithMscorlib(source, references: s_valueTupleRefs);
compilation.VerifyDiagnostics(
// (13,20): error CS8134: Deconstruction must contain at least two variables.
// var (p2) = p;
Diagnostic(ErrorCode.ERR_DeconstructTooFewElements, "p").WithLocation(13, 20),
// (13,14): error CS8130: Cannot infer the type of implicitly-typed deconstruction variable 'p2'.
// var (p2) = p;
Diagnostic(ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable, "p2").WithArguments("p2").WithLocation(13, 14)
);
}
[Fact]
[WorkItem(14876, "https://github.com/dotnet/roslyn/issues/14876")]
public void TupleTypeInDeconstruction()
{
string source = @"
class C
{
static void Main()
{
(int x, (string, long) y) = M();
System.Console.Write($""{x} {y}"");
}
static (int, (string, long)) M()
{
return (5, (""Foo"", 34983490));
}
}
";
var comp = CompileAndVerify(source, expectedOutput: "5 (Foo, 34983490)", additionalRefs: s_valueTupleRefs);
comp.VerifyDiagnostics();
}
[Fact]
[WorkItem(12468, "https://github.com/dotnet/roslyn/issues/12468")]
public void RefReturningVarInvocation()
{
string source = @"
class C
{
static int i;
static void Main()
{
int x = 0, y = 0;
(var(x, y)) = 42; // parsed as invocation
System.Console.Write(i);
}
static ref int var(int a, int b) { return ref i; }
}
";
var comp = CompileAndVerify(source, expectedOutput: "42", verify: false);
comp.VerifyDiagnostics();
}
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/15614")]
void InvokeVarForLvalueInParens()
{
......
......@@ -1968,8 +1968,7 @@ static void Main()
}
";
var comp = CompileAndVerify(source, expectedOutput: "42");
comp.VerifyDiagnostics(
);
comp.VerifyDiagnostics();
}
[Fact]
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册