提交 95a9bd8d 编写于 作者: N Neal Gafter

Bind and check the optional "named argument" style names in positional patterns

Fixes #25934
上级 170b511b
...@@ -474,10 +474,17 @@ private BoundPattern BindDeconstructionPattern(DeconstructionPatternSyntax node, ...@@ -474,10 +474,17 @@ private BoundPattern BindDeconstructionPattern(DeconstructionPatternSyntax node,
} }
for (int i = 0; i < node.SubPatterns.Count; i++) for (int i = 0; i < node.SubPatterns.Count; i++)
{ {
var subPattern = node.SubPatterns[i];
bool isError = i >= elementTypes.Length; bool isError = i >= elementTypes.Length;
TypeSymbol elementType = isError ? CreateErrorType() : elementTypes[i]; TypeSymbol elementType = isError ? CreateErrorType() : elementTypes[i];
// PROTOTYPE(patterns2): Check that node.SubPatterns[i].NameColon?.Name corresponds to tuple element i of declType. if (subPattern.NameColon != null)
BoundPattern boundSubpattern = BindPattern(node.SubPatterns[i].Pattern, elementType, isError, diagnostics); {
string name = subPattern.NameColon.Name.Identifier.ValueText;
FieldSymbol foundField = CheckIsTupleElement(subPattern.NameColon.Name, (NamedTypeSymbol)declType, name, i, diagnostics);
// PROTOTYPE(patterns2): Should the tuple field binding for the name be stored somewhere in the node?
}
BoundPattern boundSubpattern = BindPattern(subPattern.Pattern, elementType, isError, diagnostics);
patterns.Add(boundSubpattern); patterns.Add(boundSubpattern);
} }
} }
...@@ -485,19 +492,30 @@ private BoundPattern BindDeconstructionPattern(DeconstructionPatternSyntax node, ...@@ -485,19 +492,30 @@ private BoundPattern BindDeconstructionPattern(DeconstructionPatternSyntax node,
{ {
// It is not a tuple type. Seek an appropriate Deconstruct method. // It is not a tuple type. Seek an appropriate Deconstruct method.
var inputPlaceholder = new BoundImplicitReceiver(node, declType); // A fake receiver expression to permit us to reuse binding logic var inputPlaceholder = new BoundImplicitReceiver(node, declType); // A fake receiver expression to permit us to reuse binding logic
// PROTOTYPE(patterns2): include element names node.SubPatterns[i].NameColon?.Name in the AnalyzedArguments
// used in MakeDeconstructInvocationExpression so they are used to disambiguate.
BoundExpression deconstruct = MakeDeconstructInvocationExpression( BoundExpression deconstruct = MakeDeconstructInvocationExpression(
node.SubPatterns.Count, inputPlaceholder, node, diagnostics, outPlaceholders: out ImmutableArray<BoundDeconstructValuePlaceholder> outPlaceholders); node.SubPatterns.Count, inputPlaceholder, node, diagnostics, outPlaceholders: out ImmutableArray<BoundDeconstructValuePlaceholder> outPlaceholders);
deconstructMethod = deconstruct.ExpressionSymbol as MethodSymbol; deconstructMethod = deconstruct.ExpressionSymbol as MethodSymbol;
// PROTOTYPE(patterns2): Set and check the deconstructMethod int skippedExtensionParameters = deconstructMethod?.IsExtensionMethod == true ? 1 : 0;
for (int i = 0; i < node.SubPatterns.Count; i++) for (int i = 0; i < node.SubPatterns.Count; i++)
{ {
var subPattern = node.SubPatterns[i];
bool isError = outPlaceholders.IsDefaultOrEmpty || i >= outPlaceholders.Length; bool isError = outPlaceholders.IsDefaultOrEmpty || i >= outPlaceholders.Length;
TypeSymbol elementType = isError ? CreateErrorType() : outPlaceholders[i].Type; TypeSymbol elementType = isError ? CreateErrorType() : outPlaceholders[i].Type;
// PROTOTYPE(patterns2): Check that node.SubPatterns[i].NameColon?.Name corresponds to parameter i of the method. Or, if (subPattern.NameColon != null && !isError)
// better yet, include those names in the AnalyzedArguments used in MakeDeconstructInvocationExpression so they are {
// used to disambiguate. // Check that the given name is the same as the corresponding parameter of the method.
BoundPattern boundSubpattern = BindPattern(node.SubPatterns[i].Pattern, elementType, isError, diagnostics); string name = subPattern.NameColon.Name.Identifier.ValueText;
int parameterIndex = i + skippedExtensionParameters;
string parameterName = deconstructMethod.Parameters[parameterIndex].Name;
if (name != parameterName)
{
diagnostics.Add(ErrorCode.ERR_DeconstructParameterNameMistmatch, subPattern.NameColon.Name.Location, name, parameterName);
}
// PROTOTYPE(patterns2): Should the parameter binding for the name be stored somewhere in the node?
}
BoundPattern boundSubpattern = BindPattern(subPattern.Pattern, elementType, isError, diagnostics);
patterns.Add(boundSubpattern); patterns.Add(boundSubpattern);
} }
...@@ -516,6 +534,29 @@ private BoundPattern BindDeconstructionPattern(DeconstructionPatternSyntax node, ...@@ -516,6 +534,29 @@ private BoundPattern BindDeconstructionPattern(DeconstructionPatternSyntax node,
deconstruction: patterns.ToImmutableAndFree(), propertiesOpt: propertiesOpt, variable: variableSymbol, variableAccess: variableAccess, hasErrors: hasErrors); deconstruction: patterns.ToImmutableAndFree(), propertiesOpt: propertiesOpt, variable: variableSymbol, variableAccess: variableAccess, hasErrors: hasErrors);
} }
/// <summary>
/// Check that the given name designates a tuple element at the given index, and return that element.
/// </summary>
private FieldSymbol CheckIsTupleElement(SyntaxNode node, NamedTypeSymbol tupleType, string name, int tupleIndex, DiagnosticBag diagnostics)
{
FieldSymbol foundElement = null;
foreach (var symbol in tupleType.GetMembers(name))
{
if (symbol is FieldSymbol field && field.IsTupleElement())
{
foundElement = field;
break;
}
}
if (foundElement == null || foundElement.TupleElementIndex != tupleIndex)
{
diagnostics.Add(ErrorCode.ERR_TupleElementNameMismatch, node.Location, name, tupleIndex);
}
return foundElement;
}
private BoundPattern BindVarPattern(VarPatternSyntax node, TypeSymbol operandType, bool hasErrors, DiagnosticBag diagnostics) private BoundPattern BindVarPattern(VarPatternSyntax node, TypeSymbol operandType, bool hasErrors, DiagnosticBag diagnostics)
{ {
TypeSymbol declType = operandType; TypeSymbol declType = operandType;
......
...@@ -3274,6 +3274,15 @@ internal class CSharpResources { ...@@ -3274,6 +3274,15 @@ internal class CSharpResources {
} }
} }
/// <summary>
/// Looks up a localized string similar to The name &apos;{0}&apos; does not match the corresponding &apos;Deconstruct&apos; parameter &apos;{1}&apos;..
/// </summary>
internal static string ERR_DeconstructParameterNameMistmatch {
get {
return ResourceManager.GetString("ERR_DeconstructParameterNameMistmatch", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Deconstruct assignment requires an expression with a type on the right-hand-side.. /// Looks up a localized string similar to Deconstruct assignment requires an expression with a type on the right-hand-side..
/// </summary> /// </summary>
...@@ -9547,6 +9556,15 @@ internal class CSharpResources { ...@@ -9547,6 +9556,15 @@ internal class CSharpResources {
} }
} }
/// <summary>
/// Looks up a localized string similar to The name &apos;{0}&apos; does not identify tuple element {1}..
/// </summary>
internal static string ERR_TupleElementNameMismatch {
get {
return ResourceManager.GetString("ERR_TupleElementNameMismatch", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Cannot define a class or member that utilizes tuples because the compiler required type &apos;{0}&apos; cannot be found. Are you missing a reference?. /// Looks up a localized string similar to Cannot define a class or member that utilizes tuples because the compiler required type &apos;{0}&apos; cannot be found. Are you missing a reference?.
/// </summary> /// </summary>
......
...@@ -5378,4 +5378,10 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ ...@@ -5378,4 +5378,10 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<data name="ERR_SwitchGoverningExpressionRequiresParens" xml:space="preserve"> <data name="ERR_SwitchGoverningExpressionRequiresParens" xml:space="preserve">
<value>Parentheses are required around the switch governing expression.</value> <value>Parentheses are required around the switch governing expression.</value>
</data> </data>
<data name="ERR_TupleElementNameMismatch" xml:space="preserve">
<value>The name '{0}' does not identify tuple element {1}.</value>
</data>
<data name="ERR_DeconstructParameterNameMistmatch" xml:space="preserve">
<value>The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'.</value>
</data>
</root> </root>
...@@ -1597,6 +1597,8 @@ internal enum ErrorCode ...@@ -1597,6 +1597,8 @@ internal enum ErrorCode
WRN_IsTypeNamedUnderscore = 8413, WRN_IsTypeNamedUnderscore = 8413,
ERR_ExpressionTreeContainsSwitchExpression = 8414, ERR_ExpressionTreeContainsSwitchExpression = 8414,
ERR_SwitchGoverningExpressionRequiresParens = 8415, ERR_SwitchGoverningExpressionRequiresParens = 8415,
ERR_TupleElementNameMismatch = 8416,
ERR_DeconstructParameterNameMistmatch = 8417,
#endregion diagnostics introduced for recursive patterns #endregion diagnostics introduced for recursive patterns
} }
......
...@@ -8820,6 +8820,16 @@ Pokud chcete odstranit toto varování, můžete místo toho použít /reference ...@@ -8820,6 +8820,16 @@ Pokud chcete odstranit toto varování, můžete místo toho použít /reference
<target state="new">Parentheses are required around the switch governing expression.</target> <target state="new">Parentheses are required around the switch governing expression.</target>
<note /> <note />
</trans-unit> </trans-unit>
<trans-unit id="ERR_TupleElementNameMismatch">
<source>The name '{0}' does not identify tuple element {1}.</source>
<target state="new">The name '{0}' does not identify tuple element {1}.</target>
<note />
</trans-unit>
<trans-unit id="ERR_DeconstructParameterNameMistmatch">
<source>The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'.</source>
<target state="new">The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'.</target>
<note />
</trans-unit>
</body> </body>
</file> </file>
</xliff> </xliff>
\ No newline at end of file
...@@ -8820,6 +8820,16 @@ Um die Warnung zu beheben, können Sie stattdessen /reference verwenden (Einbett ...@@ -8820,6 +8820,16 @@ Um die Warnung zu beheben, können Sie stattdessen /reference verwenden (Einbett
<target state="new">Parentheses are required around the switch governing expression.</target> <target state="new">Parentheses are required around the switch governing expression.</target>
<note /> <note />
</trans-unit> </trans-unit>
<trans-unit id="ERR_TupleElementNameMismatch">
<source>The name '{0}' does not identify tuple element {1}.</source>
<target state="new">The name '{0}' does not identify tuple element {1}.</target>
<note />
</trans-unit>
<trans-unit id="ERR_DeconstructParameterNameMistmatch">
<source>The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'.</source>
<target state="new">The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'.</target>
<note />
</trans-unit>
</body> </body>
</file> </file>
</xliff> </xliff>
\ No newline at end of file
...@@ -8820,6 +8820,16 @@ Para eliminar la advertencia puede usar /reference (establezca la propiedad Embe ...@@ -8820,6 +8820,16 @@ Para eliminar la advertencia puede usar /reference (establezca la propiedad Embe
<target state="new">Parentheses are required around the switch governing expression.</target> <target state="new">Parentheses are required around the switch governing expression.</target>
<note /> <note />
</trans-unit> </trans-unit>
<trans-unit id="ERR_TupleElementNameMismatch">
<source>The name '{0}' does not identify tuple element {1}.</source>
<target state="new">The name '{0}' does not identify tuple element {1}.</target>
<note />
</trans-unit>
<trans-unit id="ERR_DeconstructParameterNameMistmatch">
<source>The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'.</source>
<target state="new">The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'.</target>
<note />
</trans-unit>
</body> </body>
</file> </file>
</xliff> </xliff>
\ No newline at end of file
...@@ -8820,6 +8820,16 @@ Pour supprimer l'avertissement, vous pouvez utiliser la commande /reference (dé ...@@ -8820,6 +8820,16 @@ Pour supprimer l'avertissement, vous pouvez utiliser la commande /reference (dé
<target state="new">Parentheses are required around the switch governing expression.</target> <target state="new">Parentheses are required around the switch governing expression.</target>
<note /> <note />
</trans-unit> </trans-unit>
<trans-unit id="ERR_TupleElementNameMismatch">
<source>The name '{0}' does not identify tuple element {1}.</source>
<target state="new">The name '{0}' does not identify tuple element {1}.</target>
<note />
</trans-unit>
<trans-unit id="ERR_DeconstructParameterNameMistmatch">
<source>The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'.</source>
<target state="new">The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'.</target>
<note />
</trans-unit>
</body> </body>
</file> </file>
</xliff> </xliff>
\ No newline at end of file
...@@ -8820,6 +8820,16 @@ Per rimuovere l'avviso, è invece possibile usare /reference (impostare la propr ...@@ -8820,6 +8820,16 @@ Per rimuovere l'avviso, è invece possibile usare /reference (impostare la propr
<target state="new">Parentheses are required around the switch governing expression.</target> <target state="new">Parentheses are required around the switch governing expression.</target>
<note /> <note />
</trans-unit> </trans-unit>
<trans-unit id="ERR_TupleElementNameMismatch">
<source>The name '{0}' does not identify tuple element {1}.</source>
<target state="new">The name '{0}' does not identify tuple element {1}.</target>
<note />
</trans-unit>
<trans-unit id="ERR_DeconstructParameterNameMistmatch">
<source>The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'.</source>
<target state="new">The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'.</target>
<note />
</trans-unit>
</body> </body>
</file> </file>
</xliff> </xliff>
\ No newline at end of file
...@@ -8820,6 +8820,16 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ ...@@ -8820,6 +8820,16 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<target state="new">Parentheses are required around the switch governing expression.</target> <target state="new">Parentheses are required around the switch governing expression.</target>
<note /> <note />
</trans-unit> </trans-unit>
<trans-unit id="ERR_TupleElementNameMismatch">
<source>The name '{0}' does not identify tuple element {1}.</source>
<target state="new">The name '{0}' does not identify tuple element {1}.</target>
<note />
</trans-unit>
<trans-unit id="ERR_DeconstructParameterNameMistmatch">
<source>The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'.</source>
<target state="new">The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'.</target>
<note />
</trans-unit>
</body> </body>
</file> </file>
</xliff> </xliff>
\ No newline at end of file
...@@ -8820,6 +8820,16 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ ...@@ -8820,6 +8820,16 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<target state="new">Parentheses are required around the switch governing expression.</target> <target state="new">Parentheses are required around the switch governing expression.</target>
<note /> <note />
</trans-unit> </trans-unit>
<trans-unit id="ERR_TupleElementNameMismatch">
<source>The name '{0}' does not identify tuple element {1}.</source>
<target state="new">The name '{0}' does not identify tuple element {1}.</target>
<note />
</trans-unit>
<trans-unit id="ERR_DeconstructParameterNameMistmatch">
<source>The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'.</source>
<target state="new">The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'.</target>
<note />
</trans-unit>
</body> </body>
</file> </file>
</xliff> </xliff>
\ No newline at end of file
...@@ -8820,6 +8820,16 @@ Aby usunąć ostrzeżenie, możesz zamiast tego użyć opcji /reference (ustaw w ...@@ -8820,6 +8820,16 @@ Aby usunąć ostrzeżenie, możesz zamiast tego użyć opcji /reference (ustaw w
<target state="new">Parentheses are required around the switch governing expression.</target> <target state="new">Parentheses are required around the switch governing expression.</target>
<note /> <note />
</trans-unit> </trans-unit>
<trans-unit id="ERR_TupleElementNameMismatch">
<source>The name '{0}' does not identify tuple element {1}.</source>
<target state="new">The name '{0}' does not identify tuple element {1}.</target>
<note />
</trans-unit>
<trans-unit id="ERR_DeconstructParameterNameMistmatch">
<source>The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'.</source>
<target state="new">The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'.</target>
<note />
</trans-unit>
</body> </body>
</file> </file>
</xliff> </xliff>
\ No newline at end of file
...@@ -8820,6 +8820,16 @@ Para incorporar informações de tipo de interoperabilidade para os dois assembl ...@@ -8820,6 +8820,16 @@ Para incorporar informações de tipo de interoperabilidade para os dois assembl
<target state="new">Parentheses are required around the switch governing expression.</target> <target state="new">Parentheses are required around the switch governing expression.</target>
<note /> <note />
</trans-unit> </trans-unit>
<trans-unit id="ERR_TupleElementNameMismatch">
<source>The name '{0}' does not identify tuple element {1}.</source>
<target state="new">The name '{0}' does not identify tuple element {1}.</target>
<note />
</trans-unit>
<trans-unit id="ERR_DeconstructParameterNameMistmatch">
<source>The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'.</source>
<target state="new">The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'.</target>
<note />
</trans-unit>
</body> </body>
</file> </file>
</xliff> </xliff>
\ No newline at end of file
...@@ -8820,6 +8820,16 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ ...@@ -8820,6 +8820,16 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<target state="new">Parentheses are required around the switch governing expression.</target> <target state="new">Parentheses are required around the switch governing expression.</target>
<note /> <note />
</trans-unit> </trans-unit>
<trans-unit id="ERR_TupleElementNameMismatch">
<source>The name '{0}' does not identify tuple element {1}.</source>
<target state="new">The name '{0}' does not identify tuple element {1}.</target>
<note />
</trans-unit>
<trans-unit id="ERR_DeconstructParameterNameMistmatch">
<source>The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'.</source>
<target state="new">The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'.</target>
<note />
</trans-unit>
</body> </body>
</file> </file>
</xliff> </xliff>
\ No newline at end of file
...@@ -8820,6 +8820,16 @@ Uyarıyı kaldırmak için, /reference kullanabilirsiniz (Birlikte Çalışma T ...@@ -8820,6 +8820,16 @@ Uyarıyı kaldırmak için, /reference kullanabilirsiniz (Birlikte Çalışma T
<target state="new">Parentheses are required around the switch governing expression.</target> <target state="new">Parentheses are required around the switch governing expression.</target>
<note /> <note />
</trans-unit> </trans-unit>
<trans-unit id="ERR_TupleElementNameMismatch">
<source>The name '{0}' does not identify tuple element {1}.</source>
<target state="new">The name '{0}' does not identify tuple element {1}.</target>
<note />
</trans-unit>
<trans-unit id="ERR_DeconstructParameterNameMistmatch">
<source>The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'.</source>
<target state="new">The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'.</target>
<note />
</trans-unit>
</body> </body>
</file> </file>
</xliff> </xliff>
\ No newline at end of file
...@@ -8820,6 +8820,16 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ ...@@ -8820,6 +8820,16 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<target state="new">Parentheses are required around the switch governing expression.</target> <target state="new">Parentheses are required around the switch governing expression.</target>
<note /> <note />
</trans-unit> </trans-unit>
<trans-unit id="ERR_TupleElementNameMismatch">
<source>The name '{0}' does not identify tuple element {1}.</source>
<target state="new">The name '{0}' does not identify tuple element {1}.</target>
<note />
</trans-unit>
<trans-unit id="ERR_DeconstructParameterNameMistmatch">
<source>The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'.</source>
<target state="new">The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'.</target>
<note />
</trans-unit>
</body> </body>
</file> </file>
</xliff> </xliff>
\ No newline at end of file
...@@ -8820,6 +8820,16 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ ...@@ -8820,6 +8820,16 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<target state="new">Parentheses are required around the switch governing expression.</target> <target state="new">Parentheses are required around the switch governing expression.</target>
<note /> <note />
</trans-unit> </trans-unit>
<trans-unit id="ERR_TupleElementNameMismatch">
<source>The name '{0}' does not identify tuple element {1}.</source>
<target state="new">The name '{0}' does not identify tuple element {1}.</target>
<note />
</trans-unit>
<trans-unit id="ERR_DeconstructParameterNameMistmatch">
<source>The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'.</source>
<target state="new">The name '{0}' does not match the corresponding 'Deconstruct' parameter '{1}'.</target>
<note />
</trans-unit>
</body> </body>
</file> </file>
</xliff> </xliff>
\ No newline at end of file
...@@ -1220,6 +1220,288 @@ void Test5() ...@@ -1220,6 +1220,288 @@ void Test5()
); );
} }
[Fact, WorkItem(25934, "https://github.com/dotnet/roslyn/issues/25934")]
public void NamesInPositionalPatterns01()
{
var source =
@"class Program
{
static void Main()
{
switch (a: 1, b: 2)
{
case (c: 2, d: 3): // error: c and d not defined
break;
}
}
}
";
var compilation = CreatePatternCompilation(source);
compilation.VerifyDiagnostics(
// (7,19): error CS8416: The name 'c' does not identify tuple element 0.
// case (c: 2, d: 3): // error: c and d not defined
Diagnostic(ErrorCode.ERR_TupleElementNameMismatch, "c").WithArguments("c", "0").WithLocation(7, 19),
// (7,25): error CS8416: The name 'd' does not identify tuple element 1.
// case (c: 2, d: 3): // error: c and d not defined
Diagnostic(ErrorCode.ERR_TupleElementNameMismatch, "d").WithArguments("d", "1").WithLocation(7, 25)
);
}
[Fact, WorkItem(25934, "https://github.com/dotnet/roslyn/issues/25934")]
public void NamesInPositionalPatterns02()
{
var source =
@"class Program
{
static void Main()
{
switch (a: 1, b: 2)
{
case (a: 2, a: 3):
break;
}
}
}
";
var compilation = CreatePatternCompilation(source);
compilation.VerifyDiagnostics(
// (7,25): error CS8416: The name 'a' does not identify tuple element 1.
// case (a: 2, a: 3):
Diagnostic(ErrorCode.ERR_TupleElementNameMismatch, "a").WithArguments("a", "1").WithLocation(7, 25)
);
}
[Fact, WorkItem(25934, "https://github.com/dotnet/roslyn/issues/25934")]
public void NamesInPositionalPatterns03()
{
var source =
@"class Program
{
static void Main()
{
switch (a: 1, b: 2)
{
case (a: 2, Item2: 3):
System.Console.WriteLine(666);
break;
case (a: 1, Item2: 2):
System.Console.WriteLine(111);
break;
}
}
}
";
var compilation = CreatePatternCompilation(source);
compilation.VerifyDiagnostics(
);
var comp = CompileAndVerify(compilation, expectedOutput: @"111");
}
[Fact, WorkItem(25934, "https://github.com/dotnet/roslyn/issues/25934")]
public void NamesInPositionalPatterns04()
{
var source =
@"class Program
{
static void Main()
{
switch (new T(a: 1, b: 2))
{
case (c: 2, d: 3):
break;
}
}
}
class T
{
public int A;
public int B;
public T(int a, int b) => (A, B) = (a, b);
public void Deconstruct(out int a, out int b) => (a, b) = (A, B);
}
";
var compilation = CreatePatternCompilation(source);
compilation.VerifyDiagnostics(
// (7,19): error CS8417: The name 'c' does not match the corresponding 'Deconstruct' parameter 'a'.
// case (c: 2, d: 3):
Diagnostic(ErrorCode.ERR_DeconstructParameterNameMistmatch, "c").WithArguments("c", "a").WithLocation(7, 19),
// (7,25): error CS8417: The name 'd' does not match the corresponding 'Deconstruct' parameter 'b'.
// case (c: 2, d: 3):
Diagnostic(ErrorCode.ERR_DeconstructParameterNameMistmatch, "d").WithArguments("d", "b").WithLocation(7, 25)
);
}
[Fact, WorkItem(25934, "https://github.com/dotnet/roslyn/issues/25934")]
public void NamesInPositionalPatterns05()
{
var source =
@"class Program
{
static void Main()
{
switch (new T(a: 1, b: 2))
{
case (c: 2, d: 3):
break;
}
}
}
class T
{
public int A;
public int B;
public T(int a, int b) => (A, B) = (a, b);
}
static class Extensions
{
public static void Deconstruct(this T t, out int a, out int b) => (a, b) = (t.A, t.B);
}
";
var compilation = CreatePatternCompilation(source);
compilation.VerifyDiagnostics(
// (7,19): error CS8417: The name 'c' does not match the corresponding 'Deconstruct' parameter 'a'.
// case (c: 2, d: 3):
Diagnostic(ErrorCode.ERR_DeconstructParameterNameMistmatch, "c").WithArguments("c", "a").WithLocation(7, 19),
// (7,25): error CS8417: The name 'd' does not match the corresponding 'Deconstruct' parameter 'b'.
// case (c: 2, d: 3):
Diagnostic(ErrorCode.ERR_DeconstructParameterNameMistmatch, "d").WithArguments("d", "b").WithLocation(7, 25)
);
}
[Fact, WorkItem(25934, "https://github.com/dotnet/roslyn/issues/25934")]
public void NamesInPositionalPatterns06()
{
var source =
@"class Program
{
static void Main()
{
switch (new T(a: 1, b: 2))
{
case (a: 2, a: 3):
break;
}
}
}
class T
{
public int A;
public int B;
public T(int a, int b) => (A, B) = (a, b);
public void Deconstruct(out int a, out int b) => (a, b) = (A, B);
}
";
var compilation = CreatePatternCompilation(source);
compilation.VerifyDiagnostics(
// (7,25): error CS8417: The name 'a' does not match the corresponding 'Deconstruct' parameter 'b'.
// case (a: 2, a: 3):
Diagnostic(ErrorCode.ERR_DeconstructParameterNameMistmatch, "a").WithArguments("a", "b").WithLocation(7, 25)
);
}
[Fact, WorkItem(25934, "https://github.com/dotnet/roslyn/issues/25934")]
public void NamesInPositionalPatterns07()
{
var source =
@"class Program
{
static void Main()
{
switch (new T(a: 1, b: 2))
{
case (a: 2, a: 3):
break;
}
}
}
class T
{
public int A;
public int B;
public T(int a, int b) => (A, B) = (a, b);
}
static class Extensions
{
public static void Deconstruct(this T t, out int a, out int b) => (a, b) = (t.A, t.B);
}
";
var compilation = CreatePatternCompilation(source);
compilation.VerifyDiagnostics(
// (7,25): error CS8417: The name 'a' does not match the corresponding 'Deconstruct' parameter 'b'.
// case (a: 2, a: 3):
Diagnostic(ErrorCode.ERR_DeconstructParameterNameMistmatch, "a").WithArguments("a", "b").WithLocation(7, 25)
);
}
[Fact, WorkItem(25934, "https://github.com/dotnet/roslyn/issues/25934")]
public void NamesInPositionalPatterns08()
{
var source =
@"class Program
{
static void Main()
{
switch (new T(a: 1, b: 2))
{
case (a: 2, b: 3):
System.Console.WriteLine(666);
break;
case (a: 1, b: 2):
System.Console.WriteLine(111);
break;
}
}
}
class T
{
public int A;
public int B;
public T(int a, int b) => (A, B) = (a, b);
public void Deconstruct(out int a, out int b) => (a, b) = (A, B);
}
";
var compilation = CreatePatternCompilation(source);
compilation.VerifyDiagnostics(
);
var comp = CompileAndVerify(compilation, expectedOutput: @"111");
}
[Fact, WorkItem(25934, "https://github.com/dotnet/roslyn/issues/25934")]
public void NamesInPositionalPatterns09()
{
var source =
@"class Program
{
static void Main()
{
switch (new T(a: 1, b: 2))
{
case (a: 2, b: 3):
System.Console.WriteLine(666);
break;
case (a: 1, b: 2):
System.Console.WriteLine(111);
break;
}
}
}
class T
{
public int A;
public int B;
public T(int a, int b) => (A, B) = (a, b);
}
static class Extensions
{
public static void Deconstruct(this T t, out int a, out int b) => (a, b) = (t.A, t.B);
}
";
var compilation = CreatePatternCompilation(source);
compilation.VerifyDiagnostics(
);
var comp = CompileAndVerify(compilation, expectedOutput: @"111");
}
// PROTOTYPE(patterns2): Need to have tests that exercise: // PROTOTYPE(patterns2): Need to have tests that exercise:
// PROTOTYPE(patterns2): Building the decision tree for the var-pattern // PROTOTYPE(patterns2): Building the decision tree for the var-pattern
// PROTOTYPE(patterns2): Definite assignment for the var-pattern // PROTOTYPE(patterns2): Definite assignment for the var-pattern
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册