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

Address non-trailing named argument test plan for C# (#21389)

上级 a33f20f3
......@@ -24,7 +24,7 @@ efforts behind them.
| [blittable](https://github.com/dotnet/csharplang/pull/206) | None | Proposal | None | | [jaredpar](https://github.com/jaredpar) |
| strongname | [strongname](https://github.com/dotnet/roslyn/tree/features/strongname) | In Progress | [Ty Overby](https://github.com/tyoverby) | | [jaredpar](https://github.com/jaredpar) |
| [interior pointer](https://github.com/dotnet/csharplang/pull/264) | None | Proposal | [vsadov](https://github.com/vsadov) | [jaredpar](https://github.com/jaredpar) | [jaredpar](https://github.com/jaredpar) |
| [non-trailing named arguments](https://github.com/dotnet/csharplang/blob/master/proposals/non-trailing-named-arguments.md) | [non-trailing](https://github.com/dotnet/roslyn/tree/features/non-trailing) | Prototype | [jcouv](https://github.com/jcouv) | TBD | [jcouv](https://github.com/jcouv) |
| [non-trailing named arguments](https://github.com/dotnet/csharplang/blob/master/proposals/non-trailing-named-arguments.md) | master | Merged | [jcouv](https://github.com/jcouv) | [gafter](https://github.com/gafter) | [jcouv](https://github.com/jcouv) |
# C# 8.0
......
......@@ -256,6 +256,8 @@ private BoundExpression BindArgListOperator(InvocationExpressionSyntax node, Dia
DiagnosticBag diagnostics,
CSharpSyntaxNode queryClause)
{
CheckNamedArgumentsForDynamicInvocation(arguments, diagnostics);
bool hasErrors = false;
if (expression.Kind == BoundKind.MethodGroup)
{
......@@ -333,6 +335,33 @@ private BoundExpression BindArgListOperator(InvocationExpressionSyntax node, Dia
hasErrors: hasErrors);
}
private void CheckNamedArgumentsForDynamicInvocation(AnalyzedArguments arguments, DiagnosticBag diagnostics)
{
if (arguments.Names.Count == 0)
{
return;
}
if (!Compilation.LanguageVersion.AllowNonTrailingNamedArguments())
{
return;
}
bool seenName = false;
for (int i = 0; i < arguments.Names.Count; i++)
{
if (arguments.Names[i] != null)
{
seenName = true;
}
else if (seenName)
{
Error(diagnostics, ErrorCode.ERR_NamedArgumentSpecificationBeforeFixedArgumentInDynamicInvocation, arguments.Arguments[i].Syntax);
return;
}
}
}
private ImmutableArray<BoundExpression> BuildArgumentsForDynamicInvocation(AnalyzedArguments arguments, DiagnosticBag diagnostics)
{
for (int i = 0; i < arguments.Arguments.Count; i++)
......
......@@ -48,7 +48,7 @@ public string Name(int i)
IdentifierNameSyntax syntax = Names[i];
return syntax == null ? null : syntax.Identifier.ValueText;
}
public ImmutableArray<string> GetNames()
{
int count = this.Names.Count;
......
......@@ -62,11 +62,12 @@ public ImmutableArray<int> ToImmutableArray()
Debug.Assert(arguments != null);
ImmutableArray<ParameterSymbol> parameters = symbol.GetParameters();
bool isVararg = symbol.GetIsVararg();
// The easy out is that we have no named arguments and are in normal form.
if (!expanded && arguments.Names.Count == 0)
{
return AnalyzeArgumentsForNormalFormNoNamedArguments(parameters, arguments, isMethodGroupConversion, symbol.GetIsVararg());
return AnalyzeArgumentsForNormalFormNoNamedArguments(parameters, arguments, isMethodGroupConversion, isVararg);
}
// We simulate an additional non-optional parameter for a vararg method.
......@@ -87,7 +88,7 @@ public ImmutableArray<int> ToImmutableArray()
// We use -1 as a sentinel to mean that no parameter was found that corresponded to this argument.
bool isNamedArgument;
int parameterPosition = CorrespondsToAnyParameter(parameters, expanded, arguments, argumentPosition,
isValidParams, out isNamedArgument, ref seenNamedParams, ref seenOutOfPositionNamedArgument) ?? -1;
isValidParams, isVararg, out isNamedArgument, ref seenNamedParams, ref seenOutOfPositionNamedArgument) ?? -1;
if (parameterPosition == -1 && unmatchedArgumentIndex == null)
{
......@@ -167,7 +168,7 @@ public ImmutableArray<int> ToImmutableArray()
}
// __arglist cannot be used with named arguments (as it doesn't have a name)
if (arguments.Names.Count != 0 && symbol.GetIsVararg())
if (arguments.Names.Any() && arguments.Names.Last() != null && isVararg)
{
return ArgumentAnalysisResult.RequiredParameterMissing(parameters.Length);
}
......@@ -223,6 +224,7 @@ public ImmutableArray<int> ToImmutableArray()
AnalyzedArguments arguments,
int argumentPosition,
bool isValidParams,
bool isVararg,
out bool isNamedArgument,
ref bool seenNamedParams,
ref bool seenOutOfPositionNamedArgument)
......@@ -273,9 +275,10 @@ public ImmutableArray<int> ToImmutableArray()
return null;
}
if (argumentPosition >= memberParameters.Length)
int parameterCount = memberParameters.Length + (isVararg ? 1 : 0);
if (argumentPosition >= parameterCount)
{
return expanded ? memberParameters.Length - 1 : (int?)null;
return expanded ? parameterCount - 1 : (int?)null;
}
return argumentPosition;
......
......@@ -6469,6 +6469,15 @@ internal class CSharpResources {
}
}
/// <summary>
/// Looks up a localized string similar to Named argument specifications must appear after all fixed arguments have been specified in a dynamic invocation..
/// </summary>
internal static string ERR_NamedArgumentSpecificationBeforeFixedArgumentInDynamicInvocation {
get {
return ResourceManager.GetString("ERR_NamedArgumentSpecificationBeforeFixedArgumentInDynamicInvocation", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Named argument &apos;{0}&apos; specifies a parameter for which a positional argument has already been given.
/// </summary>
......
......@@ -3782,6 +3782,9 @@ You should consider suppressing the warning only if you're sure that you don't w
<data name="ERR_NamedArgumentSpecificationBeforeFixedArgument" xml:space="preserve">
<value>Named argument specifications must appear after all fixed arguments have been specified. Please use language version {0} or greater to allow non-trailing named arguments.</value>
</data>
<data name="ERR_NamedArgumentSpecificationBeforeFixedArgumentInDynamicInvocation" xml:space="preserve">
<value>Named argument specifications must appear after all fixed arguments have been specified in a dynamic invocation.</value>
</data>
<data name="ERR_BadNamedArgument" xml:space="preserve">
<value>The best overload for '{0}' does not have a parameter named '{1}'</value>
</data>
......
......@@ -1498,6 +1498,7 @@ internal enum ErrorCode
WRN_UnreferencedLocalFunction = 8321,
ERR_DynamicLocalFunctionTypeParameter = 8322,
ERR_BadNonTrailingNamedArgument = 8323,
ERR_NamedArgumentSpecificationBeforeFixedArgumentInDynamicInvocation = 8324,
#endregion diagnostics introduced for C# 7.2
}
}
......@@ -190,7 +190,7 @@ internal static LanguageVersion RequiredVersion(this MessageID feature)
switch (feature)
{
// C# 7.2 features.
case MessageID.IDS_FeatureNonTrailingNamedArguments:
case MessageID.IDS_FeatureNonTrailingNamedArguments: // semantic check
return LanguageVersion.CSharp7_2;
// C# 7.1 features.
......
......@@ -157,6 +157,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Dim objectType = GetSpecialType(SpecialType.System_Object, node, diagnostics)
If Not arguments.IsEmpty Then
CheckNamedArgumentsForLateboundInvocation(argumentNames, arguments, diagnostics)
Dim builder As ArrayBuilder(Of BoundExpression) = Nothing
For i As Integer = 0 To arguments.Length - 1
......@@ -219,7 +221,32 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return New BoundLateInvocation(node, receiver, arguments, argumentNames, LateBoundAccessKind.Unknown, groupOpt, objType)
End Function
Private Sub CheckNamedArgumentsForLateboundInvocation(argumentNames As ImmutableArray(Of String),
arguments As ImmutableArray(Of BoundExpression),
diagnostics As DiagnosticBag)
Debug.Assert(Not arguments.IsDefault)
If argumentNames.IsDefault OrElse argumentNames.Count = 0 Then
Return
End If
If Not Compilation.LanguageVersion.AllowNonTrailingNamedArguments() Then
Return
End If
Dim seenName As Boolean = False
For i As Integer = 0 To argumentNames.Count - 1
If argumentNames(i) IsNot Nothing Then
seenName = True
ElseIf seenName Then
ReportDiagnostic(diagnostics, arguments(i).Syntax, ERRID.ERR_NamedArgumentSpecificationBeforeFixedArgumentInLateboundInvocation)
Return
End If
Next
End Sub
End Class
End Namespace
......@@ -1737,6 +1737,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
ERR_BadNonTrailingNamedArgument = 37302
ERR_ExpectedNamedArgumentInAttributeList = 37303
ERR_NamedArgumentSpecificationBeforeFixedArgumentInLateboundInvocation = 37304
'// WARNINGS BEGIN HERE
WRN_UseOfObsoleteSymbol2 = 40000
......
......@@ -7647,6 +7647,15 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
End Get
End Property
'''<summary>
''' Looks up a localized string similar to Named argument specifications must appear after all fixed arguments have been specified in a late bound invocation..
'''</summary>
Friend ReadOnly Property ERR_NamedArgumentSpecificationBeforeFixedArgumentInLateboundInvocation() As String
Get
Return ResourceManager.GetString("ERR_NamedArgumentSpecificationBeforeFixedArgumentInLateboundInvocation", resourceCulture)
End Get
End Property
'''<summary>
''' Looks up a localized string similar to Parameter &apos;{0}&apos; already has a matching argument..
'''</summary>
......
......@@ -717,6 +717,9 @@
<data name="ERR_ExpectedNamedArgumentInAttributeList" xml:space="preserve">
<value>Named argument expected.</value>
</data>
<data name="ERR_NamedArgumentSpecificationBeforeFixedArgumentInLateboundInvocation" xml:space="preserve">
<value>Named argument specifications must appear after all fixed arguments have been specified in a late bound invocation.</value>
</data>
<data name="ERR_ExpectedNamedArgument" xml:space="preserve">
<value>Named argument expected. Please use language version {0} or greater to use non-trailing named arguments.</value>
</data>
......
......@@ -65,10 +65,278 @@ End Class
Assert.Equal("Sub C.M(a As System.Int32, b As System.Int32)",
model.GetSymbolInfo(firstInvocation).Symbol.ToTestDisplayString())
Dim firstNamedArgA = nodes.OfType(Of NameColonEqualsSyntax)().ElementAt(0)
Assert.Equal("a:=1", firstNamedArgA.Parent.ToString())
Dim firstASymbol = model.GetSymbolInfo(firstNamedArgA.Name)
Assert.Equal(SymbolKind.Parameter, firstASymbol.Symbol.Kind)
Assert.Equal("a", firstASymbol.Symbol.Name)
Assert.Equal("Sub C.M(a As System.Int32, b As System.Int32)", firstASymbol.Symbol.ContainingSymbol.ToTestDisplayString())
Dim secondInvocation = nodes.OfType(Of InvocationExpressionSyntax)().ElementAt(3)
Assert.Equal("M(3, a:=4)", secondInvocation.ToString())
Assert.Equal("Sub C.M(b As System.Int64, a As System.Int64)",
model.GetSymbolInfo(secondInvocation).Symbol.ToTestDisplayString())
Dim secondNamedArgA = nodes.OfType(Of NameColonEqualsSyntax)().ElementAt(1)
Assert.Equal("a:=4", secondNamedArgA.Parent.ToString())
Dim secondASymbol = model.GetSymbolInfo(secondNamedArgA.Name)
Assert.Equal(SymbolKind.Parameter, secondASymbol.Symbol.Kind)
Assert.Equal("a", secondASymbol.Symbol.Name)
Assert.Equal("Sub C.M(b As System.Int64, a As System.Int64)", secondASymbol.Symbol.ContainingSymbol.ToTestDisplayString())
End Sub
<Fact>
Public Sub TestSimpleConstructor()
Dim source =
<compilation>
<file name="Program.vb">
Class C
Sub New(a As Integer, b As Integer)
System.Console.Write($"First {a} {b}. ")
End Sub
Shared Sub Main()
Dim c = New C(a:=1, 2)
End Sub
End Class
</file>
</compilation>
Dim verifier = CompileAndVerify(source, expectedOutput:="First 1 2.",
parseOptions:=TestOptions.Regular.WithLanguageVersion(LanguageVersion.VisualBasic15_5))
verifier.VerifyDiagnostics()
Dim comp = CreateCompilationWithMscorlibAndVBRuntime(source,
parseOptions:=TestOptions.Regular.WithLanguageVersion(LanguageVersion.VisualBasic15_3))
comp.AssertTheseDiagnostics(<errors>
BC30241: Named argument expected. Please use language version 15.5 or greater to use non-trailing named arguments.
Dim c = New C(a:=1, 2)
~
</errors>)
End Sub
<Fact>
Public Sub TestSimpleThis()
Dim source =
<compilation>
<file name="Program.vb">
Class C
Sub New(a As Integer, b As Integer)
System.Console.Write($"First {a} {b}. ")
End Sub
Sub New()
Me.New(a:=1, 2)
End Sub
Shared Sub Main()
Dim c = New C()
End Sub
End Class
</file>
</compilation>
Dim verifier = CompileAndVerify(source, expectedOutput:="First 1 2.",
parseOptions:=TestOptions.Regular.WithLanguageVersion(LanguageVersion.VisualBasic15_5))
verifier.VerifyDiagnostics()
Dim comp = CreateCompilationWithMscorlib45AndVBRuntime(source,
parseOptions:=TestOptions.Regular.WithLanguageVersion(LanguageVersion.VisualBasic15_3))
comp.AssertTheseDiagnostics(<errors>
BC30241: Named argument expected. Please use language version 15.5 or greater to use non-trailing named arguments.
Me.New(a:=1, 2)
~
</errors>)
End Sub
<Fact>
Public Sub TestSimpleBase()
Dim source =
<compilation>
<file name="Program.vb">
Class C
Sub New(a As Integer, b As Integer)
System.Console.Write($"First {a} {b}. ")
End Sub
End Class
Class Derived
Inherits C
Sub New()
MyBase.New(a:=1, 2)
End Sub
Shared Sub Main()
Dim derived = New Derived()
End Sub
End Class
</file>
</compilation>
Dim verifier = CompileAndVerify(source, expectedOutput:="First 1 2.",
parseOptions:=TestOptions.Regular.WithLanguageVersion(LanguageVersion.VisualBasic15_5))
verifier.VerifyDiagnostics()
End Sub
<Fact>
Public Sub TestSimpleExtension()
Dim source =
<compilation>
<file name="Program.vb"><![CDATA[
Module Extensions
<System.Runtime.CompilerServices.Extension>
Sub M(ByVal c As C, a As Integer, b As Integer)
System.Console.Write($"First {a} {b}. ")
End Sub
End Module
Class C
Shared Sub Main()
Dim c = New C()
c.M(a:=1, 2)
End Sub
End Class
]]></file>
</compilation>
Dim verifier = CompileAndVerify(source, expectedOutput:="First 1 2.",
parseOptions:=TestOptions.Regular.WithLanguageVersion(LanguageVersion.VisualBasic15_5))
verifier.VerifyDiagnostics()
Dim comp = CreateCompilationWithMscorlib45AndVBRuntime(source,
parseOptions:=TestOptions.Regular.WithLanguageVersion(LanguageVersion.VisualBasic15_3))
comp.AssertTheseDiagnostics(<errors>
BC30241: Named argument expected. Please use language version 15.5 or greater to use non-trailing named arguments.
c.M(a:=1, 2)
~
</errors>)
End Sub
<Fact>
Public Sub TestSimpleDelegate()
Dim source =
<compilation>
<file name="Program.vb"><![CDATA[
Class C
Delegate Sub MyDelegate(a As Integer, b As Integer)
Shared Sub M(a As Integer, b As Integer)
System.Console.Write($"First {a} {b}. ")
End Sub
Shared Sub Main()
Dim f As MyDelegate = AddressOf M
f(a:=1, 2)
End Sub
End Class
]]></file>
</compilation>
Dim verifier = CompileAndVerify(source, expectedOutput:="First 1 2.",
parseOptions:=TestOptions.Regular.WithLanguageVersion(LanguageVersion.VisualBasic15_5))
verifier.VerifyDiagnostics()
Dim comp = CreateCompilationWithMscorlib45AndVBRuntime(source,
parseOptions:=TestOptions.Regular.WithLanguageVersion(LanguageVersion.VisualBasic15_3))
comp.AssertTheseDiagnostics(<errors>
BC30241: Named argument expected. Please use language version 15.5 or greater to use non-trailing named arguments.
f(a:=1, 2)
~
</errors>)
End Sub
<Fact>
Public Sub TestSimpleIndexer()
Dim source =
<compilation>
<file name="Program.vb"><![CDATA[
Class C
Default ReadOnly Property Item(a As Integer, b As Integer) As Integer
Get
System.Console.Write($"First {a} {b}. ")
Return 0
End Get
End Property
Shared Sub Main()
Dim c = New C()
Dim x = c(a:=1, 2)
End Sub
End Class
]]></file>
</compilation>
Dim verifier = CompileAndVerify(source, expectedOutput:="First 1 2.",
parseOptions:=TestOptions.Regular.WithLanguageVersion(LanguageVersion.VisualBasic15_5))
verifier.VerifyDiagnostics()
Dim comp = CreateCompilationWithMscorlib45AndVBRuntime(source,
parseOptions:=TestOptions.Regular.WithLanguageVersion(LanguageVersion.VisualBasic15_3))
comp.AssertTheseDiagnostics(<errors>
BC30241: Named argument expected. Please use language version 15.5 or greater to use non-trailing named arguments.
Dim x = c(a:=1, 2)
~
</errors>)
End Sub
<Fact>
Public Sub TestSimpleError()
Dim source =
<compilation>
<file name="Program.vb"><![CDATA[
Class C
Sub New(a As Integer, b As Integer)
End Sub
Default ReadOnly Property Item(a As Integer, b As Integer) As Integer
Get
Return 0
End Get
End Property
Shared Sub Main()
Dim c = New C(b:=1, 2)
Dim x = c(b:=1, 2)
End Sub
End Class
]]></file>
</compilation>
Dim comp = CreateCompilationWithMscorlib45AndVBRuntime(source,
parseOptions:=TestOptions.Regular.WithLanguageVersion(LanguageVersion.VisualBasic15_5))
comp.AssertTheseDiagnostics(<errors>
BC37302: Named argument 'b' is used out-of-position but is followed by an unnamed argument
Dim c = New C(b:=1, 2)
~
BC37302: Named argument 'b' is used out-of-position but is followed by an unnamed argument
Dim x = c(b:=1, 2)
~
</errors>)
End Sub
<Fact>
Public Sub TestMetadataAndPESymbols()
Dim lib_vb =
<compilation>
<file name="Lib.vb"><![CDATA[
Public Class C
Public Shared Sub M(a As Integer, b As Integer)
System.Console.Write($"{a} {b}. ")
End Sub
End Class
]]></file>
</compilation>
Dim source =
<compilation>
<file name="Program.vb"><![CDATA[
Class D
Shared Sub Main()
C.M(a:=1, 2)
End Sub
End Class
]]></file>
</compilation>
Dim libComp = CreateCompilationWithMscorlibAndVBRuntime(lib_vb, parseOptions:=TestOptions.Regular.WithLanguageVersion(LanguageVersion.VisualBasic15))
Dim verifier1 = CompileAndVerify(source, expectedOutput:="1 2.", additionalRefs:={libComp.ToMetadataReference()},
parseOptions:=TestOptions.Regular.WithLanguageVersion(LanguageVersion.VisualBasic15_5))
verifier1.VerifyDiagnostics()
Dim verifier2 = CompileAndVerify(source, expectedOutput:="1 2.", additionalRefs:={libComp.EmitToImageReference()},
parseOptions:=TestOptions.Regular.WithLanguageVersion(LanguageVersion.VisualBasic15_5))
verifier2.VerifyDiagnostics()
End Sub
<Fact>
......@@ -540,6 +808,36 @@ End Class
model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString())
End Sub
<Fact>
Public Sub TestDynamicInvocation()
Dim source =
<compilation>
<file name="Program.vb">
Option Strict Off
Class C
Shared Sub Main()
Dim d = New Object()
d.M(a:=1, 2)
d.M(1, 2)
End Sub
End Class
</file>
</compilation>
Dim comp = CreateCompilationWithMscorlibAndVBRuntime(source, parseOptions:=latestParseOptions)
comp.AssertTheseDiagnostics(<errors>
BC37304: Named argument specifications must appear after all fixed arguments have been specified in a late bound invocation.
d.M(a:=1, 2)
~
</errors>)
Dim comp2 = CreateCompilationWithMscorlibAndVBRuntime(source, parseOptions:=TestOptions.Regular.WithLanguageVersion(LanguageVersion.VisualBasic15))
comp2.AssertTheseDiagnostics(<errors>
BC30241: Named argument expected. Please use language version 15.5 or greater to use non-trailing named arguments.
d.M(a:=1, 2)
~
</errors>)
End Sub
<Fact>
Public Sub TestParams()
Dim source =
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册