diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index 32a8144dc8770..f940c8ea7b476 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -4172,6 +4172,9 @@ You should consider suppressing the warning only if you're sure that you don't w An expression tree may not contain a named argument specification + + An expression tree may not contain a named argument specification out of position + An expression tree may not contain a call or invocation that uses optional arguments diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs index c312becca0b1e..e816b78cdc428 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs @@ -2397,6 +2397,7 @@ internal enum ErrorCode ERR_InitInExtension = 9304, ERR_ModifierOnUnnamedReceiverParameter = 9305, ERR_ExtensionTypeNameDisallowed = 9306, + ERR_ExpressionTreeContainsNamedArgumentOutOfPosition = 9307, // Note: you will need to do the following after adding errors: // 1) Update ErrorFacts.IsBuildOnlyDiagnostic (src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs) diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs index aeba59ca89bc7..487389d7fa908 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs @@ -2513,6 +2513,7 @@ or ErrorCode.ERR_InstanceMemberWithUnnamedExtensionsParameter or ErrorCode.ERR_InitInExtension or ErrorCode.ERR_ModifierOnUnnamedReceiverParameter or ErrorCode.ERR_ExtensionTypeNameDisallowed + or ErrorCode.ERR_ExpressionTreeContainsNamedArgumentOutOfPosition => false, }; #pragma warning restore CS8524 // The switch expression does not handle some values of its input type (it is not exhaustive) involving an unnamed enum value. diff --git a/src/Compilers/CSharp/Portable/Errors/MessageID.cs b/src/Compilers/CSharp/Portable/Errors/MessageID.cs index f2a30c73742ed..cd06dbeed0fa1 100644 --- a/src/Compilers/CSharp/Portable/Errors/MessageID.cs +++ b/src/Compilers/CSharp/Portable/Errors/MessageID.cs @@ -301,6 +301,7 @@ internal enum MessageID IDS_FeaturePartialEventsAndConstructors = MessageBase + 12852, IDS_FeatureExtensions = MessageBase + 12853, IDS_FeatureNullConditionalAssignment = MessageBase + 12854, + IDS_FeatureExpressionOptionalAndNamedArguments = MessageBase + 12855, } // Message IDs may refer to strings that need to be localized. @@ -488,6 +489,7 @@ internal static LanguageVersion RequiredVersion(this MessageID feature) case MessageID.IDS_FeaturePartialEventsAndConstructors: case MessageID.IDS_FeatureExtensions: case MessageID.IDS_FeatureNullConditionalAssignment: + case MessageID.IDS_FeatureExpressionOptionalAndNamedArguments: return LanguageVersion.Preview; // C# 13.0 features. diff --git a/src/Compilers/CSharp/Portable/Lowering/DiagnosticsPass_ExpressionTrees.cs b/src/Compilers/CSharp/Portable/Lowering/DiagnosticsPass_ExpressionTrees.cs index 947a42ec2fe1f..7eb5688d29da3 100644 --- a/src/Compilers/CSharp/Portable/Lowering/DiagnosticsPass_ExpressionTrees.cs +++ b/src/Compilers/CSharp/Portable/Lowering/DiagnosticsPass_ExpressionTrees.cs @@ -307,6 +307,7 @@ private void VisitCall( ImmutableArray arguments, ImmutableArray argumentRefKindsOpt, ImmutableArray argumentNamesOpt, + ImmutableArray argsToParamsOpt, BitVector defaultArguments, BoundNode node) { @@ -328,14 +329,22 @@ private void VisitCall( { Error(ErrorCode.ERR_ExpressionTreeContainsIndexedProperty, node); } - else if (hasDefaultArgument(arguments, defaultArguments)) + else if (hasDefaultArgument(arguments, defaultArguments) && + !_compilation.IsFeatureEnabled(MessageID.IDS_FeatureExpressionOptionalAndNamedArguments)) { Error(ErrorCode.ERR_ExpressionTreeContainsOptionalArgument, node); } - else if (!argumentNamesOpt.IsDefaultOrEmpty) + else if (!argumentNamesOpt.IsDefaultOrEmpty && + !_compilation.IsFeatureEnabled(MessageID.IDS_FeatureExpressionOptionalAndNamedArguments)) { Error(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, node); } + else if (!argumentNamesOpt.IsDefaultOrEmpty && + hasNamedArgumentOutOfOrder(argsToParamsOpt)) + { + Debug.Assert(_compilation.IsFeatureEnabled(MessageID.IDS_FeatureExpressionOptionalAndNamedArguments)); + Error(ErrorCode.ERR_ExpressionTreeContainsNamedArgumentOutOfPosition, node); + } else if (IsComCallWithRefOmitted(method, arguments, argumentRefKindsOpt)) { Error(ErrorCode.ERR_ComRefCallInExpressionTree, node); @@ -366,6 +375,22 @@ static bool hasDefaultArgument(ImmutableArray arguments, BitVec return false; } + + static bool hasNamedArgumentOutOfOrder(ImmutableArray argsToParamsOpt) + { + if (argsToParamsOpt.IsDefaultOrEmpty) + { + return false; + } + for (int i = 0; i < argsToParamsOpt.Length; i++) + { + if (argsToParamsOpt[i] != i) + { + return true; + } + } + return false; + } } public override BoundNode Visit(BoundNode node) @@ -474,7 +499,7 @@ public override BoundNode VisitCall(BoundCall node) do { - VisitCall(node.Method, null, node.Arguments, node.ArgumentRefKindsOpt, node.ArgumentNamesOpt, node.DefaultArguments, node); + visitCall(node); CheckReferenceToMethodIfLocalFunction(node, node.Method); this.VisitList(node.Arguments); } @@ -484,7 +509,7 @@ public override BoundNode VisitCall(BoundCall node) } else { - VisitCall(node.Method, null, node.Arguments, node.ArgumentRefKindsOpt, node.ArgumentNamesOpt, node.DefaultArguments, node); + visitCall(node); CheckReceiverIfField(node.ReceiverOpt); CheckReferenceToMethodIfLocalFunction(node, node.Method); this.Visit(node.ReceiverOpt); @@ -492,6 +517,11 @@ public override BoundNode VisitCall(BoundCall node) } return null; + + void visitCall(BoundCall node) + { + VisitCall(node.Method, null, node.Arguments, node.ArgumentRefKindsOpt, node.ArgumentNamesOpt, node.ArgsToParamsOpt, node.DefaultArguments, node); + } } /// @@ -520,13 +550,13 @@ public override BoundNode VisitCollectionElementInitializer(BoundCollectionEleme Error(ErrorCode.ERR_ExtensionCollectionElementInitializerInExpressionTree, node); } - VisitCall(node.AddMethod, null, node.Arguments, default(ImmutableArray), default(ImmutableArray), node.DefaultArguments, node); + VisitCall(node.AddMethod, null, node.Arguments, default(ImmutableArray), default(ImmutableArray), default(ImmutableArray), node.DefaultArguments, node); return base.VisitCollectionElementInitializer(node); } public override BoundNode VisitObjectCreationExpression(BoundObjectCreationExpression node) { - VisitCall(node.Constructor, null, node.Arguments, node.ArgumentRefKindsOpt, node.ArgumentNamesOpt, node.DefaultArguments, node); + VisitCall(node.Constructor, null, node.Arguments, node.ArgumentRefKindsOpt, node.ArgumentNamesOpt, node.ArgsToParamsOpt, node.DefaultArguments, node); return base.VisitObjectCreationExpression(node); } @@ -536,7 +566,7 @@ public override BoundNode VisitIndexerAccess(BoundIndexerAccess node) var method = indexer.GetOwnOrInheritedGetMethod() ?? indexer.GetOwnOrInheritedSetMethod(); if ((object)method != null) { - VisitCall(method, indexer, node.Arguments, node.ArgumentRefKindsOpt, node.ArgumentNamesOpt, node.DefaultArguments, node); + VisitCall(method, indexer, node.Arguments, node.ArgumentRefKindsOpt, node.ArgumentNamesOpt, node.ArgsToParamsOpt, node.DefaultArguments, node); } CheckReceiverIfField(node.ReceiverOpt); return base.VisitIndexerAccess(node); diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index de5a096eb19b8..6795aa712ec1d 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -742,6 +742,11 @@ Strom výrazů nesmí obsahovat převod obslužné rutiny interpolovaného řetězce. + + An expression tree may not contain a named argument specification out of position + An expression tree may not contain a named argument specification out of position + + An expression tree may not contain a pattern System.Index or System.Range indexer access Strom výrazů možná neobsahuje vzor přístupu indexeru System.Index nebo System.Range. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index 5f01e4ac14f17..fef82ba2dcc18 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -742,6 +742,11 @@ Eine Ausdrucksbaumstruktur darf keine Handler-Konvertierung einer interpolierten Zeichenfolge enthalten. + + An expression tree may not contain a named argument specification out of position + An expression tree may not contain a named argument specification out of position + + An expression tree may not contain a pattern System.Index or System.Range indexer access Eine Ausdrucksbaumstruktur darf keinen System.Index- oder System.Range-Musterindexerzugriff enthalten. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index 00d1fde3305e3..d39de65e1f75c 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -742,6 +742,11 @@ Un árbol de (la) expresión no puede contener una conversión de controlador de cadena interpolada. + + An expression tree may not contain a named argument specification out of position + An expression tree may not contain a named argument specification out of position + + An expression tree may not contain a pattern System.Index or System.Range indexer access Un árbol de expresión no puede contener un patrón System.Index o un acceso a indizador System.Range. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index 08fec5ecba140..a7c0e82371b41 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -742,6 +742,11 @@ Une arborescence de l’expression ne peut pas contenir une conversion de gestionnaire de chaîne interpolée. + + An expression tree may not contain a named argument specification out of position + An expression tree may not contain a named argument specification out of position + + An expression tree may not contain a pattern System.Index or System.Range indexer access Une arborescence de l'expression ne peut pas contenir de modèle d'accès à l'indexeur System.Index ou System.Range diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index 0fc4adbafaa8d..3c9c4b638996c 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -742,6 +742,11 @@ Un albero delle espressioni non può contenere una conversione del gestore di stringhe interpolate. + + An expression tree may not contain a named argument specification out of position + An expression tree may not contain a named argument specification out of position + + An expression tree may not contain a pattern System.Index or System.Range indexer access Un albero delle espressioni non può contenere un accesso a indicizzatore System.Index o System.Range di criterio diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index 48ea332b42990..89652d71d304c 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -742,6 +742,11 @@ 式ツリーには、補間された文字列ハンドラー変換を含めることはできません。 + + An expression tree may not contain a named argument specification out of position + An expression tree may not contain a named argument specification out of position + + An expression tree may not contain a pattern System.Index or System.Range indexer access 式ツリーに、System.Index または System.Range インデクサー アクセスのパターンを含めることはできません diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index 775bfea7ecee3..2931f97754d3c 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -742,6 +742,11 @@ 식 트리에는 보간된 문자열 처리기 변환이 포함될 수 없습니다. + + An expression tree may not contain a named argument specification out of position + An expression tree may not contain a named argument specification out of position + + An expression tree may not contain a pattern System.Index or System.Range indexer access 식 트리에는 System.Index 또는 System.Range 패턴의 인덱서 액세스를 포함할 수 없습니다. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index d8945a8b30892..9aa2a31cfa12c 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -742,6 +742,11 @@ Drzewo wyrażenia nie może zawierać konwersji procedury obsługi ciągu interpolowanego. + + An expression tree may not contain a named argument specification out of position + An expression tree may not contain a named argument specification out of position + + An expression tree may not contain a pattern System.Index or System.Range indexer access Drzewo wyrażenia nie może zawierać dostępu do indeksatora z wzorcem System.Index lub System.Range diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index 25e773f0f604c..327398efa7c86 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -742,6 +742,11 @@ Uma árvore de expressão pode não conter uma conversão de manipulador de cadeia de caracteres interpolada. + + An expression tree may not contain a named argument specification out of position + An expression tree may not contain a named argument specification out of position + + An expression tree may not contain a pattern System.Index or System.Range indexer access Uma árvore de expressão não pode conter um padrão System.Index ou acesso do indexador System.Range diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index d65d0bd1b4e90..8e43ce0310444 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -742,6 +742,11 @@ Дерево выражения не может содержать преобразование обработчика интерполированных строк. + + An expression tree may not contain a named argument specification out of position + An expression tree may not contain a named argument specification out of position + + An expression tree may not contain a pattern System.Index or System.Range indexer access Дерево выражения не может содержать доступ к индексатору System.Index или System.Range шаблона. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index 2761233d364d1..70a0bc99f2505 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -742,6 +742,11 @@ Bir ifade ağacı, düz metin arasına kod eklenmiş dize işleyicisi dönüşümü içeremez. + + An expression tree may not contain a named argument specification out of position + An expression tree may not contain a named argument specification out of position + + An expression tree may not contain a pattern System.Index or System.Range indexer access İfade ağacı, desen System.Index veya System.Range dizin oluşturucu erişimi içeremez diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index e5200e28058c4..741909a05e9bc 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -742,6 +742,11 @@ 表达式树可能不包含内插字符串处理程序转换。 + + An expression tree may not contain a named argument specification out of position + An expression tree may not contain a named argument specification out of position + + An expression tree may not contain a pattern System.Index or System.Range indexer access 表达式树不能包含模式 System.Index 或 System.Range 索引器访问 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index f19961cb87432..72d9bb03d5892 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -742,6 +742,11 @@ 運算式樹狀架構不可包含差補字串處理常式轉換。 + + An expression tree may not contain a named argument specification out of position + An expression tree may not contain a named argument specification out of position + + An expression tree may not contain a pattern System.Index or System.Range indexer access 運算式樹狀架構不可包含 System.Index 或 System.Range 索引子存取模式 diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenExprLambdaTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenExprLambdaTests.cs index 2a479263ed080..a79f04945d6b0 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenExprLambdaTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenExprLambdaTests.cs @@ -2595,8 +2595,9 @@ static void Main() CompileAndVerifyUtil(text, expectedOutput: TrimExpectedOutput(expectedOutput)); } - [Fact] - public void MethodCallWithParams3() + [Theory] + [MemberData(nameof(LanguageVersions13AndNewer))] + public void MethodCallWithParams3(LanguageVersion languageVersion) { var text = @"using System; @@ -2612,12 +2613,20 @@ static void Main() Console.WriteLine(testExpr); } }"; - CreateCompilationWithMscorlib40AndSystemCore(text) - .VerifyDiagnostics( - // (10,48): error CS0854: An expression tree may not contain a call or invocation that uses optional arguments - // Expression> testExpr = () => ModAdd2(); - Diagnostic(ErrorCode.ERR_ExpressionTreeContainsOptionalArgument, "ModAdd2()") - ); + var comp = CreateCompilationWithMscorlib40AndSystemCore(text, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), options: TestOptions.ReleaseExe); + if (languageVersion == LanguageVersion.CSharp13) + { + comp.VerifyDiagnostics( + // (10,48): error CS0854: An expression tree may not contain a call or invocation that uses optional arguments + // Expression> testExpr = () => ModAdd2(); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsOptionalArgument, "ModAdd2()") + ); + } + else + { + var verifier = CompileAndVerify(comp, expectedOutput: "() => ModAdd2(3, 4, new [] {})"); + verifier.VerifyDiagnostics(); + } } [WorkItem(544419, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544419")] diff --git a/src/Compilers/CSharp/Test/Emit3/Semantics/ExpressionOptionalAndNamedArgumentsTests.cs b/src/Compilers/CSharp/Test/Emit3/Semantics/ExpressionOptionalAndNamedArgumentsTests.cs new file mode 100644 index 0000000000000..6cda4a6ea0db4 --- /dev/null +++ b/src/Compilers/CSharp/Test/Emit3/Semantics/ExpressionOptionalAndNamedArgumentsTests.cs @@ -0,0 +1,1991 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#nullable disable + +using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Microsoft.CodeAnalysis.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests +{ + public class ExpressionOptionalAndNamedArgumentsTests : CSharpTestBase + { + private static string GetUtilities(bool useExpression) + { + return useExpression ? + """ + using System; + using System.Linq.Expressions; + public static class Utils + { + public static void Report(Expression> f) + { + object value = Run(f); + Console.WriteLine("{0}: {1}", f, value is null ? "null" : value.ToString()); + } + public static T Run(Expression> e) + { + var f = e.Compile(); + return f(); + } + } + """ : + """ + using System; + public static class Utils + { + public static void Report(Func f) + { + object value = Run(f); + Console.WriteLine("--: {0}", value is null ? "null" : value.ToString()); + } + public static T Run(Func f) + { + return f(); + } + } + """; + } + + private static string IncludeExpression(bool useExpression, string expectedOutput) + { + if (useExpression) + { + return expectedOutput; + } + var builder = new System.Text.StringBuilder(); + using var reader = new System.IO.StringReader(expectedOutput); + while (reader.ReadLine() is { } line) + { + int index = line.IndexOf(':'); + if (index >= 0) + { + builder.Append("--"); + builder.AppendLine(line.Substring(index)); + } + else + { + builder.AppendLine(line); + } + } + return builder.ToString(); + } + + [Theory] + [CombinatorialData] + public void OptionalParameter_01( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersion.Preview, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion, + [CombinatorialValues("", "in", "ref readonly")] string refKind, + bool useExpression, + bool useCompilationReference) + { + string sourceA = $$""" + #pragma warning disable 9200 // default value is specified for 'ref readonly' parameter + public static class A + { + public static T GetValue({{refKind}} T t = default) => t; + } + """; + var comp = CreateCompilation(sourceA); + var refA = AsReference(comp, useCompilationReference); + + string sourceB = $$""" + struct S + { + } + class Program + { + static void Main() + { + Utils.Report(() => A.GetValue()); + Utils.Report(() => A.GetValue()); + Utils.Report(() => A.GetValue()); + } + } + """; + comp = CreateCompilation( + [sourceB, GetUtilities(useExpression)], + references: [refA], + parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), + options: TestOptions.ReleaseExe); + if (languageVersion == LanguageVersion.CSharp13 && useExpression) + { + comp.VerifyEmitDiagnostics( + // (8,28): error CS0854: An expression tree may not contain a call or invocation that uses optional arguments + // Utils.Report(() => A.GetValue()); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsOptionalArgument, "A.GetValue()").WithLocation(8, 28), + // (9,28): error CS0854: An expression tree may not contain a call or invocation that uses optional arguments + // Utils.Report(() => A.GetValue()); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsOptionalArgument, "A.GetValue()").WithLocation(9, 28), + // (10,28): error CS0854: An expression tree may not contain a call or invocation that uses optional arguments + // Utils.Report(() => A.GetValue()); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsOptionalArgument, "A.GetValue()").WithLocation(10, 28)); + } + else + { + var verifier = CompileAndVerify( + comp, + expectedOutput: IncludeExpression(useExpression, """ + () => GetValue(0): 0 + () => GetValue(null): null + () => GetValue(value(S)): S + """)); + verifier.VerifyDiagnostics(); + } + } + + [Theory] + [CombinatorialData] + public void OptionalParameter_02( + [CombinatorialValues("", "in", "ref readonly")] string refKind, + bool useExpression, + bool useCompilationReference) + { + string sourceA = $$""" + #pragma warning disable 9200 // default value is specified for 'ref readonly' parameter + public static class A + { + public static int GetIntValue({{refKind}} int i = 10) => i; + public static string GetStringValue({{refKind}} string s = "default") => s; + public static object GetObjectValue({{refKind}} object o = null) => o; + } + """; + var comp = CreateCompilation(sourceA); + var refA = AsReference(comp, useCompilationReference); + + string sourceB = $$""" + class Program + { + static void Main() + { + Utils.Report(() => A.GetIntValue()); + Utils.Report(() => A.GetStringValue()); + Utils.Report(() => A.GetObjectValue()); + } + } + """; + var verifier = CompileAndVerify( + [sourceB, GetUtilities(useExpression)], + references: [refA], + expectedOutput: IncludeExpression(useExpression, """ + () => GetIntValue(10): 10 + () => GetStringValue("default"): default + () => GetObjectValue(null): null + """)); + verifier.VerifyDiagnostics(); + } + + [Theory] + [CombinatorialData] + public void OptionalParameter_AndParams( + [CombinatorialValues("", "in", "ref readonly")] string refKind, + bool useExpression, + bool useCompilationReference) + { + string sourceA = $$""" + #pragma warning disable 9200 // default value is specified for 'ref readonly' parameter + public static class A + { + public static T GetValue({{refKind}} T x, {{refKind}} T y = default, params T[] args) => y; + } + """; + var comp = CreateCompilation(sourceA); + var refA = AsReference(comp, useCompilationReference); + + string sourceB = $$""" + struct S + { + } + class Program + { + static void Main() + { + Utils.Report(() => A.GetValue(1)); + Utils.Report(() => A.GetValue(2, 3, 4)); + } + } + """; + var verifier = CompileAndVerify( + [sourceB, GetUtilities(useExpression)], + references: [refA], + expectedOutput: IncludeExpression(useExpression, """ + () => GetValue(1, 0, new [] {}): 0 + () => GetValue(2, 3, new [] {4}): 3 + """)); + if (refKind == "ref readonly") + { + verifier.VerifyDiagnostics( + // (8,44): warning CS9193: Argument 1 should be a variable because it is passed to a 'ref readonly' parameter + // Utils.Report(() => A.GetValue(1)); + Diagnostic(ErrorCode.WRN_RefReadonlyNotVariable, "1").WithArguments("1").WithLocation(8, 44), + // (9,44): warning CS9193: Argument 1 should be a variable because it is passed to a 'ref readonly' parameter + // Utils.Report(() => A.GetValue(2, 3, 4)); + Diagnostic(ErrorCode.WRN_RefReadonlyNotVariable, "2").WithArguments("1").WithLocation(9, 44), + // (9,47): warning CS9193: Argument 2 should be a variable because it is passed to a 'ref readonly' parameter + // Utils.Report(() => A.GetValue(2, 3, 4)); + Diagnostic(ErrorCode.WRN_RefReadonlyNotVariable, "3").WithArguments("2").WithLocation(9, 47)); + } + else + { + verifier.VerifyDiagnostics(); + } + } + + [Theory] + [CombinatorialData] + public void OptionalParameter_Overloads_01( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersion.Preview, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion, + bool useExpression, + bool useCompilationReference) + { + string sourceA = $$""" + public static class A + { + public static (int, int, int) GetArgs(int x, int y = -2, params int[] z) => (x, y, z.Length); + public static object GetArgs(object x) => x; + } + """; + var comp = CreateCompilation(sourceA); + var refA = AsReference(comp, useCompilationReference); + + string sourceB = $$""" + class Program + { + static void Main() + { + Utils.Report(() => A.GetArgs(10, 20)); + Utils.Report(() => A.GetArgs(10)); + } + } + """; + comp = CreateCompilation( + [sourceB, GetUtilities(useExpression)], + references: [refA], + parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), + options: TestOptions.ReleaseExe); + if (languageVersion == LanguageVersion.CSharp13 && useExpression) + { + comp.VerifyEmitDiagnostics( + // (6,28): error CS0854: An expression tree may not contain a call or invocation that uses optional arguments + // Utils.Report(() => A.GetArgs(10)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsOptionalArgument, "A.GetArgs(10)").WithLocation(6, 28)); + } + else + { + var verifier = CompileAndVerify( + comp, + expectedOutput: IncludeExpression(useExpression, """ + () => GetArgs(10, 20, new [] {}): (10, 20, 0) + () => GetArgs(10, -2, new [] {}): (10, -2, 0) + """)); + verifier.VerifyDiagnostics(); + } + } + + [Theory] + [CombinatorialData] + public void OptionalParameter_Overloads_02( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersion.Preview, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion, + bool useExpression, + bool useCompilationReference) + { + string sourceA = $$""" + public static class A + { + public static (int, int, int) GetArgs(int x, int y, int z = -3) => (x, y, z); + public static (int, int) GetArgs(int x, params int[] y) => (x, y.Length); + } + """; + var comp = CreateCompilation(sourceA); + var refA = AsReference(comp, useCompilationReference); + + string sourceB = $$""" + class Program + { + static void Main() + { + Utils.Report(() => A.GetArgs(10, 20, 30)); + Utils.Report(() => A.GetArgs(10, 20)); + } + } + """; + comp = CreateCompilation( + [sourceB, GetUtilities(useExpression)], + references: [refA], + parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), + options: TestOptions.ReleaseExe); + if (languageVersion == LanguageVersion.CSharp13 && useExpression) + { + comp.VerifyEmitDiagnostics( + // (6,28): error CS0854: An expression tree may not contain a call or invocation that uses optional arguments + // Utils.Report(() => A.GetArgs(10, 20)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsOptionalArgument, "A.GetArgs(10, 20)").WithLocation(6, 28)); + } + else + { + var verifier = CompileAndVerify( + comp, + expectedOutput: IncludeExpression(useExpression, """ + () => GetArgs(10, 20, 30): (10, 20, 30) + () => GetArgs(10, 20, -3): (10, 20, -3) + """)); + verifier.VerifyDiagnostics(); + } + } + + [Theory] + [CombinatorialData] + public void OptionalParameter_Constructor( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersion.Preview, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion, + bool useExpression) + { + string sourceA = $$""" + public class A + { + public readonly string X; + public readonly int Y; + public A(string x = "default", in int y = 10) { X = x; Y = y; } + public override string ToString() => $"({X}, {Y})"; + } + """; + var comp = CreateCompilation(sourceA); + var refA = comp.EmitToImageReference(); + + string sourceB = $$""" + class Program + { + static void Main() + { + Utils.Report(() => new A("str")); + Utils.Report(() => new A()); + } + } + """; + comp = CreateCompilation( + [sourceB, GetUtilities(useExpression)], + references: [refA], + parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), + options: TestOptions.ReleaseExe); + if (languageVersion == LanguageVersion.CSharp13 && useExpression) + { + comp.VerifyEmitDiagnostics( + // (5,28): error CS0854: An expression tree may not contain a call or invocation that uses optional arguments + // Utils.Report(() => new A("str")); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsOptionalArgument, @"new A(""str"")").WithLocation(5, 28), + // (6,28): error CS0854: An expression tree may not contain a call or invocation that uses optional arguments + // Utils.Report(() => new A()); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsOptionalArgument, "new A()").WithLocation(6, 28)); + } + else + { + var verifier = CompileAndVerify( + comp, + expectedOutput: IncludeExpression(useExpression, """ + () => new A("str", 10): (str, 10) + () => new A("default", 10): (default, 10) + """)); + verifier.VerifyDiagnostics(); + } + } + + [Theory] + [CombinatorialData] + public void OptionalParameter_Indexer( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersion.Preview, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion, + bool useExpression) + { + string sourceA = $$""" + public class A + { + public int this[int x, int y = 10] => y; + } + """; + var comp = CreateCompilation(sourceA); + var refA = comp.EmitToImageReference(); + + string sourceB = $$""" + class Program + { + static void Main() + { + var a = new A(); + Utils.Report(() => a[1, 2]); + Utils.Report(() => a[3]); + } + } + """; + comp = CreateCompilation( + [sourceB, GetUtilities(useExpression)], + references: [refA], + parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), + options: TestOptions.ReleaseExe); + if (languageVersion == LanguageVersion.CSharp13 && useExpression) + { + comp.VerifyEmitDiagnostics( + // (7,28): error CS0854: An expression tree may not contain a call or invocation that uses optional arguments + // Utils.Report(() => a[3]); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsOptionalArgument, "a[3]").WithLocation(7, 28)); + } + else + { + var verifier = CompileAndVerify( + comp, + expectedOutput: IncludeExpression(useExpression, """ + () => value(Program+<>c__DisplayClass0_0).a.get_Item(1, 2): 2 + () => value(Program+<>c__DisplayClass0_0).a.get_Item(3, 10): 10 + """)); + verifier.VerifyDiagnostics(); + } + } + + [Theory] + [CombinatorialData] + public void OptionalParameter_Delegate( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersion.Preview, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion, + bool useExpression) + { + string sourceA = $$""" + public delegate int D(int x, in int y = 10); + """; + var comp = CreateCompilation(sourceA); + var refA = comp.EmitToImageReference(); + + string sourceB = $$""" + class Program + { + static void Main() + { + D d = F; + Utils.Report(() => d(1, 2)); + Utils.Report(() => d(3)); + } + static T F(T x, in T y) => y; + } + """; + comp = CreateCompilation( + [sourceB, GetUtilities(useExpression)], + references: [refA], + parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), + options: TestOptions.ReleaseExe); + if (languageVersion == LanguageVersion.CSharp13 && useExpression) + { + comp.VerifyEmitDiagnostics( + // (7,28): error CS0854: An expression tree may not contain a call or invocation that uses optional arguments + // Utils.Report(() => d(3)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsOptionalArgument, "d(3)").WithLocation(7, 28)); + } + else + { + var verifier = CompileAndVerify( + comp, + expectedOutput: IncludeExpression(useExpression, """ + () => Invoke(value(Program+<>c__DisplayClass0_0).d, 1, 2): 2 + () => Invoke(value(Program+<>c__DisplayClass0_0).d, 3, 10): 10 + """)); + verifier.VerifyDiagnostics(); + } + } + + [Theory] + [CombinatorialData] + public void OptionalParameter_CollectionInitializer( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersion.Preview, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion, + [CombinatorialValues("", "in", "ref readonly")] string refKind, + bool useExpression) + { + string sourceA = $$""" + #pragma warning disable 9200 // default value is specified for 'ref readonly' parameter + using System.Collections; + using System.Collections.Generic; + using System.Text; + class MyCollection : IEnumerable + { + private List> _list = new(); + public void Add({{refKind}} K k = default, {{refKind}} V v = default) { _list.Add(new(k, v)); } + public IEnumerator> GetEnumerator() => _list.GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + public override string ToString() + { + var builder = new StringBuilder(); + foreach (var kvp in this) + { + if (builder.Length > 0) builder.Append(", "); + builder.AppendFormat("({0}, {1})", kvp.Key, kvp.Value); + } + return builder.ToString(); + } + } + """; + string sourceB = """ + #pragma warning disable 9193 // Argument should be a variable because it is passed to a 'ref readonly' parameter + class Program + { + static void Main() + { + Utils.Report(() => new MyCollection() { { "one", 1 }, { "two" } }); + } + } + """; + var comp = CreateCompilation( + [sourceA, sourceB, GetUtilities(useExpression)], + parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), + options: TestOptions.ReleaseExe); + if (languageVersion == LanguageVersion.CSharp13 && useExpression) + { + comp.VerifyEmitDiagnostics( + // (6,76): error CS0854: An expression tree may not contain a call or invocation that uses optional arguments + // Utils.Report(() => new MyCollection() { { "one", 1 }, { "two" } }); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsOptionalArgument, @"{ ""two"" }").WithLocation(6, 76)); + } + else if (refKind != "") + { + // Expression does not support initializers with ref parameters at runtime. + comp.VerifyEmitDiagnostics(); + } + else + { + var verifier = CompileAndVerify( + comp, + expectedOutput: IncludeExpression(useExpression, """ + () => new MyCollection`2() {Void Add(System.String, Int32)("one", 1), Void Add(System.String, Int32)("two", 0)}: (one, 1), (two, 0) + """)); + verifier.VerifyDiagnostics(); + } + } + + [Theory] + [CombinatorialData] + public void OptionalParameter_LocalFunction( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersion.Preview, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion) + { + string source = """ + using System; + using System.Linq.Expressions; + class Program + { + static void Main() + { + Expression> e; + T Local(T t = default) => t; + Local(10); + Local(); + e = () => Local(20); + e = () => Local(); + } + } + """; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + if (languageVersion == LanguageVersion.CSharp13) + { + comp.VerifyEmitDiagnostics( + // (11,19): error CS8110: An expression tree may not contain a reference to a local function + // e = () => Local(20); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsLocalFunction, "Local(20)").WithLocation(11, 19), + // (12,19): error CS0854: An expression tree may not contain a call or invocation that uses optional arguments + // e = () => Local(); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsOptionalArgument, "Local()").WithLocation(12, 19)); + } + else + { + comp.VerifyEmitDiagnostics( + // (11,19): error CS8110: An expression tree may not contain a reference to a local function + // e = () => Local(20); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsLocalFunction, "Local(20)").WithLocation(11, 19), + // (12,19): error CS8110: An expression tree may not contain a reference to a local function + // e = () => Local(); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsLocalFunction, "Local()").WithLocation(12, 19)); + } + } + + [Theory] + [CombinatorialData] + public void Decimal( + bool useExpression, + bool useCompilationReference) + { + string sourceA = """ + public static class A + { + public static decimal GetValue(decimal d = 100) => d; + } + """; + var comp = CreateCompilation(sourceA); + var refA = AsReference(comp, useCompilationReference); + + string sourceB = $$""" + class Program + { + static void Main() + { + Utils.Report(() => A.GetValue(200)); + Utils.Report(() => A.GetValue()); + } + } + """; + var verifier = CompileAndVerify( + [sourceB, GetUtilities(useExpression)], + references: [refA], + expectedOutput: IncludeExpression(useExpression, """ + () => GetValue(200): 200 + () => GetValue(100): 100 + """)); + verifier.VerifyDiagnostics(); + } + + [Theory] + [CombinatorialData] + public void DateTime_01( + bool useExpression, + bool useCompilationReference) + { + string sourceA = """ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + public static class A + { + public static DateTime GetValue([Optional][DateTimeConstant(100)] DateTime value) => value; + } + """; + var comp = CreateCompilation(sourceA); + var refA = AsReference(comp, useCompilationReference); + + string sourceB = $$""" + using System; + class Program + { + static void Main() + { + Utils.Report(() => A.GetValue(new DateTime(200)).Ticks); + Utils.Report(() => A.GetValue().Ticks); + } + } + """; + var verifier = CompileAndVerify( + [sourceB, GetUtilities(useExpression)], + references: [refA], + expectedOutput: IncludeExpression(useExpression, """ + () => GetValue(new DateTime(200)).Ticks: 200 + () => GetValue(new DateTime(100)).Ticks: 100 + """)); + verifier.VerifyDiagnostics(); + } + + [Theory] + [CombinatorialData] + public void DateTime_02( + bool useExpression, + bool useCompilationReference) + { + string sourceA = """ + using System; + using System.Runtime.CompilerServices; + public static class A + { + public static DateTime GetValue([DateTimeConstant(100)] DateTime value) => value; + } + """; + var comp = CreateCompilation(sourceA); + var refA = AsReference(comp, useCompilationReference); + + string sourceB = $$""" + class Program + { + static void Main() + { + Utils.Report(() => A.GetValue().Ticks); + } + } + """; + comp = CreateCompilation( + [sourceB, GetUtilities(useExpression)], + references: [refA]); + comp.VerifyEmitDiagnostics( + // (5,30): error CS7036: There is no argument given that corresponds to the required parameter 'value' of 'A.GetValue(DateTime)' + // Utils.Report(() => A.GetValue().Ticks); + Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "GetValue").WithArguments("value", "A.GetValue(System.DateTime)").WithLocation(5, 30)); + } + + [Theory] + [CombinatorialData] + public void OptionalAndDefaultParameterValue( + bool includeOptional, + bool includeDefaultParameterValue, + bool useExpression, + bool useCompilationReference) + { + string sourceA = $$""" + using System.Runtime.InteropServices; + public static class A + { + public static int GetValue( + {{(includeOptional ? "[Optional]" : "")}} + {{(includeDefaultParameterValue ? "[DefaultParameterValue(100)]" : "")}} + int value) => value; + } + """; + var comp = CreateCompilation(sourceA); + var refA = AsReference(comp, useCompilationReference); + + string sourceB = """ + class Program + { + static void Main() + { + Utils.Report(() => A.GetValue(200)); + Utils.Report(() => A.GetValue()); + } + } + """; + comp = CreateCompilation( + [sourceB, GetUtilities(useExpression)], + references: [refA], + options: TestOptions.ReleaseExe); + if (includeOptional) + { + string parameterValue = includeDefaultParameterValue ? "100" : "0"; + var verifier = CompileAndVerify( + comp, + expectedOutput: IncludeExpression(useExpression, $$""" + () => GetValue(200): 200 + () => GetValue({{parameterValue}}): {{parameterValue}} + """)); + verifier.VerifyDiagnostics(); + } + else + { + comp.VerifyEmitDiagnostics( + // (6,30): error CS7036: There is no argument given that corresponds to the required parameter 'value' of 'A.GetValue(int)' + // Utils.Report(() => A.GetValue()); + Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "GetValue").WithArguments("value", "A.GetValue(int)").WithLocation(6, 30)); + } + } + + [Theory] + [CombinatorialData] + public void OptionalParams( + bool includeDefaultParameterValue, + bool useExpression, + bool useCompilationReference) + { + string sourceA = $$""" + using System.Runtime.InteropServices; + public static class A + { + public static string GetValue( + [Optional] + {{(includeDefaultParameterValue ? "[DefaultParameterValue(null)]" : "")}} + params int[] args) + { + return (args is null) ? "null" : args.Length.ToString(); + } + } + """; + var comp = CreateCompilation(sourceA); + var refA = AsReference(comp, useCompilationReference); + + string sourceB = """ + class Program + { + static void Main() + { + Utils.Report(() => A.GetValue(1, 2, 3)); + Utils.Report(() => A.GetValue()); + } + } + """; + var verifier = CompileAndVerify( + [sourceB, GetUtilities(useExpression)], + references: [refA], + expectedOutput: IncludeExpression(useExpression, """ + () => GetValue(new [] {1, 2, 3}): 3 + () => GetValue(new [] {}): 0 + """)); + verifier.VerifyDiagnostics(); + } + + [Theory] + [CombinatorialData] + public void NamedArgument_01( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersion.Preview, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion, + bool useExpression, + bool useCompilationReference) + { + string sourceA = $$""" + public static class A + { + public static T GetFirst(T first, T second) => first; + } + """; + var comp = CreateCompilation(sourceA); + var refA = AsReference(comp, useCompilationReference); + + string sourceB1 = $$""" + class Program + { + static void Main() + { + Utils.Report(() => A.GetFirst(1, second:2)); + Utils.Report(() => A.GetFirst(first: 1, 2)); + Utils.Report(() => A.GetFirst(first: 1, second:2)); + } + } + """; + comp = CreateCompilation( + [sourceB1, GetUtilities(useExpression)], + references: [refA], + parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), + options: TestOptions.ReleaseExe); + if (languageVersion == LanguageVersion.CSharp13 && useExpression) + { + comp.VerifyEmitDiagnostics( + // (5,28): error CS0853: An expression tree may not contain a named argument specification + // Utils.Report(() => A.GetFirst(1, second:2)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, "A.GetFirst(1, second:2)").WithLocation(5, 28), + // (6,28): error CS0853: An expression tree may not contain a named argument specification + // Utils.Report(() => A.GetFirst(first: 1, 2)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, "A.GetFirst(first: 1, 2)").WithLocation(6, 28), + // (7,28): error CS0853: An expression tree may not contain a named argument specification + // Utils.Report(() => A.GetFirst(first: 1, second:2)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, "A.GetFirst(first: 1, second:2)").WithLocation(7, 28)); + } + else + { + var verifier = CompileAndVerify( + comp, + expectedOutput: IncludeExpression(useExpression, """ + () => GetFirst(1, 2): 1 + () => GetFirst(1, 2): 1 + () => GetFirst(1, 2): 1 + """)); + verifier.VerifyDiagnostics(); + } + + string sourceB2 = $$""" + class Program + { + static void Main() + { + Utils.Report(() => A.GetFirst(second:2, first: 1)); + } + } + """; + comp = CreateCompilation( + [sourceB2, GetUtilities(useExpression)], + references: [refA], + parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), + options: TestOptions.ReleaseExe); + if (languageVersion == LanguageVersion.CSharp13 && useExpression) + { + comp.VerifyEmitDiagnostics( + // (5,28): error CS0853: An expression tree may not contain a named argument specification + // Utils.Report(() => A.GetFirst(second:2, first: 1)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, "A.GetFirst(second:2, first: 1)").WithLocation(5, 28)); + } + else if (useExpression) + { + comp.VerifyEmitDiagnostics( + // (5,28): error CS9307: An expression tree may not contain a named argument specification out of position + // Utils.Report(() => A.GetFirst(second:2, first: 1)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgumentOutOfPosition, "A.GetFirst(second:2, first: 1)").WithLocation(5, 28)); + } + else + { + var verifier = CompileAndVerify( + comp, + expectedOutput: """ + --: 1 + """); + verifier.VerifyDiagnostics(); + } + + string sourceB3 = $$""" + class Program + { + static void Main() + { + Utils.Report(() => A.GetFirst(2, first: 1)); + Utils.Report(() => A.GetFirst(second:2, 1)); + } + } + """; + comp = CreateCompilation( + [sourceB3, GetUtilities(useExpression)], + references: [refA], + parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), + options: TestOptions.ReleaseExe); + comp.VerifyEmitDiagnostics( + // (5,47): error CS1744: Named argument 'first' specifies a parameter for which a positional argument has already been given + // Utils.Report(() => A.GetFirst(2, first: 1)); + Diagnostic(ErrorCode.ERR_NamedArgumentUsedInPositional, "first").WithArguments("first").WithLocation(5, 47), + // (6,44): error CS8323: Named argument 'second' is used out-of-position but is followed by an unnamed argument + // Utils.Report(() => A.GetFirst(second:2, 1)); + Diagnostic(ErrorCode.ERR_BadNonTrailingNamedArgument, "second").WithArguments("second").WithLocation(6, 44)); + } + + [Theory] + [CombinatorialData] + public void NamedArgument_02( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersion.Preview, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion, + bool useExpression, + bool useCompilationReference) + { + string sourceA = $$""" + public static class A + { + public static T GetFirst(T first = default, T second = default, T third = default) => first; + } + """; + var comp = CreateCompilation(sourceA); + var refA = AsReference(comp, useCompilationReference); + + string sourceB1 = $$""" + class Program + { + static void Main() + { + Utils.Report(() => A.GetFirst(first: 1, second: 2, third: 3)); + Utils.Report(() => A.GetFirst(first: 1, 2, 3)); + Utils.Report(() => A.GetFirst(first: 1, 2)); + Utils.Report(() => A.GetFirst(first: 1)); + Utils.Report(() => A.GetFirst(1, second: 2, 3)); + Utils.Report(() => A.GetFirst(1, second: 2)); + Utils.Report(() => A.GetFirst(1, 2, third: 3)); + } + } + """; + comp = CreateCompilation( + [sourceB1, GetUtilities(useExpression)], + references: [refA], + parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), + options: TestOptions.ReleaseExe); + if (languageVersion == LanguageVersion.CSharp13 && useExpression) + { + comp.VerifyEmitDiagnostics( + // (5,28): error CS0853: An expression tree may not contain a named argument specification + // Utils.Report(() => A.GetFirst(first: 1, second: 2, third: 3)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, "A.GetFirst(first: 1, second: 2, third: 3)").WithLocation(5, 28), + // (6,28): error CS0853: An expression tree may not contain a named argument specification + // Utils.Report(() => A.GetFirst(first: 1, 2, 3)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, "A.GetFirst(first: 1, 2, 3)").WithLocation(6, 28), + // (7,28): error CS0854: An expression tree may not contain a call or invocation that uses optional arguments + // Utils.Report(() => A.GetFirst(first: 1, 2)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsOptionalArgument, "A.GetFirst(first: 1, 2)").WithLocation(7, 28), + // (8,28): error CS0854: An expression tree may not contain a call or invocation that uses optional arguments + // Utils.Report(() => A.GetFirst(first: 1)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsOptionalArgument, "A.GetFirst(first: 1)").WithLocation(8, 28), + // (9,28): error CS0853: An expression tree may not contain a named argument specification + // Utils.Report(() => A.GetFirst(1, second: 2, 3)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, "A.GetFirst(1, second: 2, 3)").WithLocation(9, 28), + // (10,28): error CS0854: An expression tree may not contain a call or invocation that uses optional arguments + // Utils.Report(() => A.GetFirst(1, second: 2)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsOptionalArgument, "A.GetFirst(1, second: 2)").WithLocation(10, 28), + // (11,28): error CS0853: An expression tree may not contain a named argument specification + // Utils.Report(() => A.GetFirst(1, 2, third: 3)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, "A.GetFirst(1, 2, third: 3)").WithLocation(11, 28)); + } + else + { + var verifier = CompileAndVerify( + comp, + expectedOutput: IncludeExpression(useExpression, """ + () => GetFirst(1, 2, 3): 1 + () => GetFirst(1, 2, 3): 1 + () => GetFirst(1, 2, 0): 1 + () => GetFirst(1, 0, 0): 1 + () => GetFirst(1, 2, 3): 1 + () => GetFirst(1, 2, 0): 1 + () => GetFirst(1, 2, 3): 1 + """)); + verifier.VerifyDiagnostics(); + } + + string sourceB2 = $$""" + class Program + { + static void Main() + { + Utils.Report(() => A.GetFirst(third:3, second: 2, first: 1)); + Utils.Report(() => A.GetFirst(second:2, first: 1)); + Utils.Report(() => A.GetFirst(second:2, third: 3)); + Utils.Report(() => A.GetFirst(second:2)); + Utils.Report(() => A.GetFirst(third:3, second: 2)); + Utils.Report(() => A.GetFirst(third:3)); + Utils.Report(() => A.GetFirst()); + } + } + """; + comp = CreateCompilation( + [sourceB2, GetUtilities(useExpression)], + references: [refA], + parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), + options: TestOptions.ReleaseExe); + if (languageVersion == LanguageVersion.CSharp13 && useExpression) + { + comp.VerifyEmitDiagnostics( + // (5,28): error CS0853: An expression tree may not contain a named argument specification + // Utils.Report(() => A.GetFirst(third:3, second: 2, first: 1)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, "A.GetFirst(third:3, second: 2, first: 1)").WithLocation(5, 28), + // (6,28): error CS0854: An expression tree may not contain a call or invocation that uses optional arguments + // Utils.Report(() => A.GetFirst(second:2, first: 1)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsOptionalArgument, "A.GetFirst(second:2, first: 1)").WithLocation(6, 28), + // (7,28): error CS0854: An expression tree may not contain a call or invocation that uses optional arguments + // Utils.Report(() => A.GetFirst(second:2, third: 3)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsOptionalArgument, "A.GetFirst(second:2, third: 3)").WithLocation(7, 28), + // (8,28): error CS0854: An expression tree may not contain a call or invocation that uses optional arguments + // Utils.Report(() => A.GetFirst(second:2)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsOptionalArgument, "A.GetFirst(second:2)").WithLocation(8, 28), + // (9,28): error CS0854: An expression tree may not contain a call or invocation that uses optional arguments + // Utils.Report(() => A.GetFirst(third:3, second: 2)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsOptionalArgument, "A.GetFirst(third:3, second: 2)").WithLocation(9, 28), + // (10,28): error CS0854: An expression tree may not contain a call or invocation that uses optional arguments + // Utils.Report(() => A.GetFirst(third:3)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsOptionalArgument, "A.GetFirst(third:3)").WithLocation(10, 28), + // (11,28): error CS0854: An expression tree may not contain a call or invocation that uses optional arguments + // Utils.Report(() => A.GetFirst()); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsOptionalArgument, "A.GetFirst()").WithLocation(11, 28)); + } + else if (useExpression) + { + comp.VerifyEmitDiagnostics( + // (5,28): error CS9307: An expression tree may not contain a named argument specification out of position + // Utils.Report(() => A.GetFirst(third:3, second: 2, first: 1)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgumentOutOfPosition, "A.GetFirst(third:3, second: 2, first: 1)").WithLocation(5, 28), + // (6,28): error CS9307: An expression tree may not contain a named argument specification out of position + // Utils.Report(() => A.GetFirst(second:2, first: 1)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgumentOutOfPosition, "A.GetFirst(second:2, first: 1)").WithLocation(6, 28), + // (7,28): error CS9307: An expression tree may not contain a named argument specification out of position + // Utils.Report(() => A.GetFirst(second:2, third: 3)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgumentOutOfPosition, "A.GetFirst(second:2, third: 3)").WithLocation(7, 28), + // (8,28): error CS9307: An expression tree may not contain a named argument specification out of position + // Utils.Report(() => A.GetFirst(second:2)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgumentOutOfPosition, "A.GetFirst(second:2)").WithLocation(8, 28), + // (9,28): error CS9307: An expression tree may not contain a named argument specification out of position + // Utils.Report(() => A.GetFirst(third:3, second: 2)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgumentOutOfPosition, "A.GetFirst(third:3, second: 2)").WithLocation(9, 28), + // (10,28): error CS9307: An expression tree may not contain a named argument specification out of position + // Utils.Report(() => A.GetFirst(third:3)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgumentOutOfPosition, "A.GetFirst(third:3)").WithLocation(10, 28)); + } + else + { + var verifier = CompileAndVerify( + comp, + expectedOutput: """ + --: 1 + --: 1 + --: 0 + --: 0 + --: 0 + --: 0 + --: 0 + """); + verifier.VerifyDiagnostics(); + } + } + + [Theory] + [CombinatorialData] + public void NamedArgument_03( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersion.Preview, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion, + bool useExpression, + bool useCompilationReference) + { + string sourceA = $$""" + public static class A + { + public static (T, int?) GetFirstAndParamsLength(T first, params T[] more) => (first, more?.Length); + } + """; + var comp = CreateCompilation(sourceA); + var refA = AsReference(comp, useCompilationReference); + + string sourceB1 = $$""" + class Program + { + static void Main() + { + Utils.Report(() => A.GetFirstAndParamsLength(first: 1)); + Utils.Report(() => A.GetFirstAndParamsLength(first: 1, 2)); + Utils.Report(() => A.GetFirstAndParamsLength(first: 1, 2, 3)); + Utils.Report(() => A.GetFirstAndParamsLength(1, more: default)); + Utils.Report(() => A.GetFirstAndParamsLength(1, more: new[] { 2, 3 })); + Utils.Report(() => A.GetFirstAndParamsLength(first: 1, more: default)); + } + } + """; + comp = CreateCompilation( + [sourceB1, GetUtilities(useExpression)], + references: [refA], + parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), + options: TestOptions.ReleaseExe); + if (languageVersion == LanguageVersion.CSharp13 && useExpression) + { + comp.VerifyEmitDiagnostics( + // (5,28): error CS0853: An expression tree may not contain a named argument specification + // Utils.Report(() => A.GetFirstAndParamsLength(first: 1)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, "A.GetFirstAndParamsLength(first: 1)").WithLocation(5, 28), + // (6,28): error CS0853: An expression tree may not contain a named argument specification + // Utils.Report(() => A.GetFirstAndParamsLength(first: 1, 2)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, "A.GetFirstAndParamsLength(first: 1, 2)").WithLocation(6, 28), + // (7,28): error CS0853: An expression tree may not contain a named argument specification + // Utils.Report(() => A.GetFirstAndParamsLength(first: 1, 2, 3)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, "A.GetFirstAndParamsLength(first: 1, 2, 3)").WithLocation(7, 28), + // (8,28): error CS0853: An expression tree may not contain a named argument specification + // Utils.Report(() => A.GetFirstAndParamsLength(1, more: default)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, "A.GetFirstAndParamsLength(1, more: default)").WithLocation(8, 28), + // (9,28): error CS0853: An expression tree may not contain a named argument specification + // Utils.Report(() => A.GetFirstAndParamsLength(1, more: new[] { 2, 3 })); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, "A.GetFirstAndParamsLength(1, more: new[] { 2, 3 })").WithLocation(9, 28), + // (10,28): error CS0853: An expression tree may not contain a named argument specification + // Utils.Report(() => A.GetFirstAndParamsLength(first: 1, more: default)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, "A.GetFirstAndParamsLength(first: 1, more: default)").WithLocation(10, 28)); + } + else + { + var verifier = CompileAndVerify( + comp, + expectedOutput: IncludeExpression(useExpression, """ + () => GetFirstAndParamsLength(1, new [] {}): (1, 0) + () => GetFirstAndParamsLength(1, new [] {2}): (1, 1) + () => GetFirstAndParamsLength(1, new [] {2, 3}): (1, 2) + () => GetFirstAndParamsLength(1, null): (1, ) + () => GetFirstAndParamsLength(1, new [] {2, 3}): (1, 2) + () => GetFirstAndParamsLength(1, null): (1, ) + """)); + verifier.VerifyDiagnostics(); + } + + string sourceB2 = $$""" + class Program + { + static void Main() + { + Utils.Report(() => A.GetFirstAndParamsLength(more: default, first: 1)); + } + } + """; + comp = CreateCompilation( + [sourceB2, GetUtilities(useExpression)], + references: [refA], + parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), + options: TestOptions.ReleaseExe); + if (languageVersion == LanguageVersion.CSharp13 && useExpression) + { + comp.VerifyEmitDiagnostics( + // (5,28): error CS0853: An expression tree may not contain a named argument specification + // Utils.Report(() => A.GetFirstAndParamsLength(more: default, first: 1)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, "A.GetFirstAndParamsLength(more: default, first: 1)").WithLocation(5, 28)); + } + else if (useExpression) + { + comp.VerifyEmitDiagnostics( + // (5,28): error CS9307: An expression tree may not contain a named argument specification out of position + // Utils.Report(() => A.GetFirstAndParamsLength(more: default, first: 1)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgumentOutOfPosition, "A.GetFirstAndParamsLength(more: default, first: 1)").WithLocation(5, 28)); + } + else + { + var verifier = CompileAndVerify( + comp, + expectedOutput: """ + --: (1, ) + """); + verifier.VerifyDiagnostics(); + } + + string sourceB3 = $$""" + class Program + { + static void Main() + { + Utils.Report(() => A.GetFirstAndParamsLength()); + Utils.Report(() => A.GetFirstAndParamsLength(more: default)); + Utils.Report(() => A.GetFirstAndParamsLength(more: default, 1)); + Utils.Report(() => A.GetFirstAndParamsLength(default, first: 1)); + } + } + """; + comp = CreateCompilation( + [sourceB3, GetUtilities(useExpression)], + references: [refA], + parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), + options: TestOptions.ReleaseExe); + comp.VerifyEmitDiagnostics( + // (5,30): error CS7036: There is no argument given that corresponds to the required parameter 'first' of 'A.GetFirstAndParamsLength(T, params T[])' + // Utils.Report(() => A.GetFirstAndParamsLength()); + Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "GetFirstAndParamsLength").WithArguments("first", "A.GetFirstAndParamsLength(T, params T[])").WithLocation(5, 30), + // (6,30): error CS7036: There is no argument given that corresponds to the required parameter 'first' of 'A.GetFirstAndParamsLength(T, params T[])' + // Utils.Report(() => A.GetFirstAndParamsLength(more: default)); + Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "GetFirstAndParamsLength").WithArguments("first", "A.GetFirstAndParamsLength(T, params T[])").WithLocation(6, 30), + // (7,59): error CS8323: Named argument 'more' is used out-of-position but is followed by an unnamed argument + // Utils.Report(() => A.GetFirstAndParamsLength(more: default, 1)); + Diagnostic(ErrorCode.ERR_BadNonTrailingNamedArgument, "more").WithArguments("more").WithLocation(7, 59), + // (8,63): error CS1744: Named argument 'first' specifies a parameter for which a positional argument has already been given + // Utils.Report(() => A.GetFirstAndParamsLength(default, first: 1)); + Diagnostic(ErrorCode.ERR_NamedArgumentUsedInPositional, "first").WithArguments("first").WithLocation(8, 63)); + } + + [Theory] + [CombinatorialData] + public void NamedArgument_04( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersion.Preview, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion, + bool useExpression, + bool useCompilationReference) + { + string sourceA = $$""" + public static class A + { + public static (T, int?) GetSecondAndParamsLength(T first = default, T second = default, params T[] more) => (second, more?.Length); + } + """; + var comp = CreateCompilation(sourceA); + var refA = AsReference(comp, useCompilationReference); + + string sourceB1 = $$""" + class Program + { + static void Main() + { + Utils.Report(() => A.GetSecondAndParamsLength()); + Utils.Report(() => A.GetSecondAndParamsLength(first: 1)); + Utils.Report(() => A.GetSecondAndParamsLength(first: 1, 2)); + Utils.Report(() => A.GetSecondAndParamsLength(first: 1, 2, 3, 4)); + Utils.Report(() => A.GetSecondAndParamsLength(first: 1, second: 2)); + Utils.Report(() => A.GetSecondAndParamsLength(first: 1, second: 2, more: default)); + Utils.Report(() => A.GetSecondAndParamsLength(first: 1, 2, more: new[] { 3 })); + Utils.Report(() => A.GetSecondAndParamsLength(1)); + Utils.Report(() => A.GetSecondAndParamsLength(1, second: 2)); + Utils.Report(() => A.GetSecondAndParamsLength(1, second: 2, 3, 4)); + Utils.Report(() => A.GetSecondAndParamsLength(1, second: 2, more: default)); + Utils.Report(() => A.GetSecondAndParamsLength(1, 2, more: default)); + } + } + """; + comp = CreateCompilation( + [sourceB1, GetUtilities(useExpression)], + references: [refA], + parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), + options: TestOptions.ReleaseExe); + if (languageVersion == LanguageVersion.CSharp13 && useExpression) + { + comp.VerifyEmitDiagnostics( + // (5,28): error CS0854: An expression tree may not contain a call or invocation that uses optional arguments + // Utils.Report(() => A.GetSecondAndParamsLength()); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsOptionalArgument, "A.GetSecondAndParamsLength()").WithLocation(5, 28), + // (6,28): error CS0854: An expression tree may not contain a call or invocation that uses optional arguments + // Utils.Report(() => A.GetSecondAndParamsLength(first: 1)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsOptionalArgument, "A.GetSecondAndParamsLength(first: 1)").WithLocation(6, 28), + // (7,28): error CS0853: An expression tree may not contain a named argument specification + // Utils.Report(() => A.GetSecondAndParamsLength(first: 1, 2)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, "A.GetSecondAndParamsLength(first: 1, 2)").WithLocation(7, 28), + // (8,28): error CS0853: An expression tree may not contain a named argument specification + // Utils.Report(() => A.GetSecondAndParamsLength(first: 1, 2, 3, 4)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, "A.GetSecondAndParamsLength(first: 1, 2, 3, 4)").WithLocation(8, 28), + // (9,28): error CS0853: An expression tree may not contain a named argument specification + // Utils.Report(() => A.GetSecondAndParamsLength(first: 1, second: 2)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, "A.GetSecondAndParamsLength(first: 1, second: 2)").WithLocation(9, 28), + // (10,28): error CS0853: An expression tree may not contain a named argument specification + // Utils.Report(() => A.GetSecondAndParamsLength(first: 1, second: 2, more: default)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, "A.GetSecondAndParamsLength(first: 1, second: 2, more: default)").WithLocation(10, 28), + // (11,28): error CS0853: An expression tree may not contain a named argument specification + // Utils.Report(() => A.GetSecondAndParamsLength(first: 1, 2, more: new[] { 3 })); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, "A.GetSecondAndParamsLength(first: 1, 2, more: new[] { 3 })").WithLocation(11, 28), + // (12,28): error CS0854: An expression tree may not contain a call or invocation that uses optional arguments + // Utils.Report(() => A.GetSecondAndParamsLength(1)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsOptionalArgument, "A.GetSecondAndParamsLength(1)").WithLocation(12, 28), + // (13,28): error CS0853: An expression tree may not contain a named argument specification + // Utils.Report(() => A.GetSecondAndParamsLength(1, second: 2)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, "A.GetSecondAndParamsLength(1, second: 2)").WithLocation(13, 28), + // (14,28): error CS0853: An expression tree may not contain a named argument specification + // Utils.Report(() => A.GetSecondAndParamsLength(1, second: 2, 3, 4)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, "A.GetSecondAndParamsLength(1, second: 2, 3, 4)").WithLocation(14, 28), + // (15,28): error CS0853: An expression tree may not contain a named argument specification + // Utils.Report(() => A.GetSecondAndParamsLength(1, second: 2, more: default)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, "A.GetSecondAndParamsLength(1, second: 2, more: default)").WithLocation(15, 28), + // (16,28): error CS0853: An expression tree may not contain a named argument specification + // Utils.Report(() => A.GetSecondAndParamsLength(1, 2, more: default)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, "A.GetSecondAndParamsLength(1, 2, more: default)").WithLocation(16, 28)); + } + else + { + var verifier = CompileAndVerify( + comp, + expectedOutput: IncludeExpression(useExpression, """ + () => GetSecondAndParamsLength(null, null, new [] {}): (, 0) + () => GetSecondAndParamsLength(1, 0, new [] {}): (0, 0) + () => GetSecondAndParamsLength(1, 2, new [] {}): (2, 0) + () => GetSecondAndParamsLength(1, 2, new [] {3, 4}): (2, 2) + () => GetSecondAndParamsLength(1, 2, new [] {}): (2, 0) + () => GetSecondAndParamsLength(1, 2, null): (2, ) + () => GetSecondAndParamsLength(1, 2, new [] {3}): (2, 1) + () => GetSecondAndParamsLength(1, 0, new [] {}): (0, 0) + () => GetSecondAndParamsLength(1, 2, new [] {}): (2, 0) + () => GetSecondAndParamsLength(1, 2, new [] {3, 4}): (2, 2) + () => GetSecondAndParamsLength(1, 2, null): (2, ) + () => GetSecondAndParamsLength(1, 2, null): (2, ) + """)); + verifier.VerifyDiagnostics(); + } + + string sourceB2 = $$""" + class Program + { + static void Main() + { + Utils.Report(() => A.GetSecondAndParamsLength(first: 1, second: 2, 3, 4)); + Utils.Report(() => A.GetSecondAndParamsLength(first: 1, more: default, second: 2)); + Utils.Report(() => A.GetSecondAndParamsLength(first: 1, more: default)); + Utils.Report(() => A.GetSecondAndParamsLength(second: 2)); + Utils.Report(() => A.GetSecondAndParamsLength(second: 2, first: 1)); + Utils.Report(() => A.GetSecondAndParamsLength(second: 2, more: default)); + Utils.Report(() => A.GetSecondAndParamsLength(more: new[] { 3, 4 })); + Utils.Report(() => A.GetSecondAndParamsLength(more: new[] { 3, 4 }, second: 2, first: 1)); + } + } + """; + comp = CreateCompilation( + [sourceB2, GetUtilities(useExpression)], + references: [refA], + parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), + options: TestOptions.ReleaseExe); + if (languageVersion == LanguageVersion.CSharp13 && useExpression) + { + comp.VerifyEmitDiagnostics( + // (5,28): error CS0853: An expression tree may not contain a named argument specification + // Utils.Report(() => A.GetSecondAndParamsLength(first: 1, second: 2, 3, 4)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, "A.GetSecondAndParamsLength(first: 1, second: 2, 3, 4)").WithLocation(5, 28), + // (6,28): error CS0853: An expression tree may not contain a named argument specification + // Utils.Report(() => A.GetSecondAndParamsLength(first: 1, more: default, second: 2)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, "A.GetSecondAndParamsLength(first: 1, more: default, second: 2)").WithLocation(6, 28), + // (7,28): error CS0854: An expression tree may not contain a call or invocation that uses optional arguments + // Utils.Report(() => A.GetSecondAndParamsLength(first: 1, more: default)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsOptionalArgument, "A.GetSecondAndParamsLength(first: 1, more: default)").WithLocation(7, 28), + // (8,28): error CS0854: An expression tree may not contain a call or invocation that uses optional arguments + // Utils.Report(() => A.GetSecondAndParamsLength(second: 2)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsOptionalArgument, "A.GetSecondAndParamsLength(second: 2)").WithLocation(8, 28), + // (9,28): error CS0853: An expression tree may not contain a named argument specification + // Utils.Report(() => A.GetSecondAndParamsLength(second: 2, first: 1)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, "A.GetSecondAndParamsLength(second: 2, first: 1)").WithLocation(9, 28), + // (10,28): error CS0854: An expression tree may not contain a call or invocation that uses optional arguments + // Utils.Report(() => A.GetSecondAndParamsLength(second: 2, more: default)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsOptionalArgument, "A.GetSecondAndParamsLength(second: 2, more: default)").WithLocation(10, 28), + // (11,28): error CS0854: An expression tree may not contain a call or invocation that uses optional arguments + // Utils.Report(() => A.GetSecondAndParamsLength(more: new[] { 3, 4 })); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsOptionalArgument, "A.GetSecondAndParamsLength(more: new[] { 3, 4 })").WithLocation(11, 28), + // (12,28): error CS0853: An expression tree may not contain a named argument specification + // Utils.Report(() => A.GetSecondAndParamsLength(more: new[] { 3, 4 }, second: 2, first: 1)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, "A.GetSecondAndParamsLength(more: new[] { 3, 4 }, second: 2, first: 1)").WithLocation(12, 28)); + } + else if (useExpression) + { + comp.VerifyEmitDiagnostics( + // (6,28): error CS9307: An expression tree may not contain a named argument specification out of position + // Utils.Report(() => A.GetSecondAndParamsLength(first: 1, more: default, second: 2)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgumentOutOfPosition, "A.GetSecondAndParamsLength(first: 1, more: default, second: 2)").WithLocation(6, 28), + // (7,28): error CS9307: An expression tree may not contain a named argument specification out of position + // Utils.Report(() => A.GetSecondAndParamsLength(first: 1, more: default)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgumentOutOfPosition, "A.GetSecondAndParamsLength(first: 1, more: default)").WithLocation(7, 28), + // (8,28): error CS9307: An expression tree may not contain a named argument specification out of position + // Utils.Report(() => A.GetSecondAndParamsLength(second: 2)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgumentOutOfPosition, "A.GetSecondAndParamsLength(second: 2)").WithLocation(8, 28), + // (9,28): error CS9307: An expression tree may not contain a named argument specification out of position + // Utils.Report(() => A.GetSecondAndParamsLength(second: 2, first: 1)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgumentOutOfPosition, "A.GetSecondAndParamsLength(second: 2, first: 1)").WithLocation(9, 28), + // (10,28): error CS9307: An expression tree may not contain a named argument specification out of position + // Utils.Report(() => A.GetSecondAndParamsLength(second: 2, more: default)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgumentOutOfPosition, "A.GetSecondAndParamsLength(second: 2, more: default)").WithLocation(10, 28), + // (11,28): error CS9307: An expression tree may not contain a named argument specification out of position + // Utils.Report(() => A.GetSecondAndParamsLength(more: new[] { 3, 4 })); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgumentOutOfPosition, "A.GetSecondAndParamsLength(more: new[] { 3, 4 })").WithLocation(11, 28), + // (12,28): error CS9307: An expression tree may not contain a named argument specification out of position + // Utils.Report(() => A.GetSecondAndParamsLength(more: new[] { 3, 4 }, second: 2, first: 1)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgumentOutOfPosition, "A.GetSecondAndParamsLength(more: new[] { 3, 4 }, second: 2, first: 1)").WithLocation(12, 28)); + } + else + { + var verifier = CompileAndVerify( + comp, + expectedOutput: """ + --: (2, 2) + --: (2, ) + --: (0, ) + --: (2, 0) + --: (2, 0) + --: (2, ) + --: (0, 2) + --: (2, 2) + """); + verifier.VerifyDiagnostics(); + } + + string sourceB3 = $$""" + class Program + { + static void Main() + { + Utils.Report(() => A.GetSecondAndParamsLength(second: 2, default)); + Utils.Report(() => A.GetSecondAndParamsLength(second: 2, first: 1, default)); + Utils.Report(() => A.GetSecondAndParamsLength(second: 2, first: 1, 3, 4)); + Utils.Report(() => A.GetSecondAndParamsLength(second: 2, more: default, 1)); + Utils.Report(() => A.GetSecondAndParamsLength(more: default, default)); + } + } + """; + comp = CreateCompilation( + [sourceB3, GetUtilities(useExpression)], + references: [refA], + parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), + options: TestOptions.ReleaseExe); + comp.VerifyEmitDiagnostics( + // (5,55): error CS8323: Named argument 'second' is used out-of-position but is followed by an unnamed argument + // Utils.Report(() => A.GetSecondAndParamsLength(second: 2, default)); + Diagnostic(ErrorCode.ERR_BadNonTrailingNamedArgument, "second").WithArguments("second").WithLocation(5, 55), + // (6,55): error CS8323: Named argument 'second' is used out-of-position but is followed by an unnamed argument + // Utils.Report(() => A.GetSecondAndParamsLength(second: 2, first: 1, default)); + Diagnostic(ErrorCode.ERR_BadNonTrailingNamedArgument, "second").WithArguments("second").WithLocation(6, 55), + // (7,55): error CS8323: Named argument 'second' is used out-of-position but is followed by an unnamed argument + // Utils.Report(() => A.GetSecondAndParamsLength(second: 2, first: 1, 3, 4)); + Diagnostic(ErrorCode.ERR_BadNonTrailingNamedArgument, "second").WithArguments("second").WithLocation(7, 55), + // (8,55): error CS8323: Named argument 'second' is used out-of-position but is followed by an unnamed argument + // Utils.Report(() => A.GetSecondAndParamsLength(second: 2, more: default, 1)); + Diagnostic(ErrorCode.ERR_BadNonTrailingNamedArgument, "second").WithArguments("second").WithLocation(8, 55), + // (9,63): error CS8323: Named argument 'more' is used out-of-position but is followed by an unnamed argument + // Utils.Report(() => A.GetSecondAndParamsLength(more: default, default)); + Diagnostic(ErrorCode.ERR_BadNonTrailingNamedArgument, "more").WithArguments("more").WithLocation(9, 63)); + } + + [Theory] + [CombinatorialData] + public void NamedArgument_OverloadsDifferentOrder( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersion.Preview, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion, + bool useExpression, + bool useCompilationReference) + { + string sourceA = $$""" + public static class A + { + public static int GetFirst(int first, int second) => first; + public static string GetFirst(string second, string first) => first ?? "null"; + } + """; + var comp = CreateCompilation(sourceA); + var refA = AsReference(comp, useCompilationReference); + + string sourceB1 = $$""" + class Program + { + static void Main() + { + Utils.Report(() => A.GetFirst(first: 1, second: 2)); + Utils.Report(() => A.GetFirst(second: "two", first: "one")); + } + } + """; + comp = CreateCompilation( + [sourceB1, GetUtilities(useExpression)], + references: [refA], + parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), + options: TestOptions.ReleaseExe); + if (languageVersion == LanguageVersion.CSharp13 && useExpression) + { + comp.VerifyEmitDiagnostics( + // (5,28): error CS0853: An expression tree may not contain a named argument specification + // Utils.Report(() => A.GetFirst(first: 1, second: 2)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, "A.GetFirst(first: 1, second: 2)").WithLocation(5, 28), + // (6,28): error CS0853: An expression tree may not contain a named argument specification + // Utils.Report(() => A.GetFirst(second: "two", first: "one")); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, @"A.GetFirst(second: ""two"", first: ""one"")").WithLocation(6, 28)); + } + else + { + var verifier = CompileAndVerify( + comp, + expectedOutput: IncludeExpression(useExpression, """ + () => GetFirst(1, 2): 1 + () => GetFirst("two", "one"): one + """)); + verifier.VerifyDiagnostics(); + } + + string sourceB2 = $$""" + class Program + { + static void Main() + { + Utils.Report(() => A.GetFirst(second: 2, first: 1)); + Utils.Report(() => A.GetFirst(first: "one", second: "two")); + } + } + """; + comp = CreateCompilation( + [sourceB2, GetUtilities(useExpression)], + references: [refA], + parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), + options: TestOptions.ReleaseExe); + if (languageVersion == LanguageVersion.CSharp13 && useExpression) + { + comp.VerifyEmitDiagnostics( + // (5,28): error CS0853: An expression tree may not contain a named argument specification + // Utils.Report(() => A.GetFirst(second: 2, first: 1)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, "A.GetFirst(second: 2, first: 1)").WithLocation(5, 28), + // (6,28): error CS0853: An expression tree may not contain a named argument specification + // Utils.Report(() => A.GetFirst(first: "one", second: "two")); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, @"A.GetFirst(first: ""one"", second: ""two"")").WithLocation(6, 28)); + } + else if (useExpression) + { + comp.VerifyEmitDiagnostics( + // (5,28): error CS9307: An expression tree may not contain a named argument specification out of position + // Utils.Report(() => A.GetFirst(second: 2, first: 1)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgumentOutOfPosition, "A.GetFirst(second: 2, first: 1)").WithLocation(5, 28), + // (6,28): error CS9307: An expression tree may not contain a named argument specification out of position + // Utils.Report(() => A.GetFirst(first: "one", second: "two")); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgumentOutOfPosition, @"A.GetFirst(first: ""one"", second: ""two"")").WithLocation(6, 28)); + } + else + { + var verifier = CompileAndVerify( + comp, + expectedOutput: """ + --: 1 + --: one + """); + verifier.VerifyDiagnostics(); + } + + string sourceB3 = $$""" + class Program + { + static void Main() + { + Utils.Report(() => A.GetFirst(first: default, default)); + Utils.Report(() => A.GetFirst(second: default, default)); + Utils.Report(() => A.GetFirst(default, second: default)); + Utils.Report(() => A.GetFirst(default, first: default)); + } + } + """; + comp = CreateCompilation( + [sourceB3, GetUtilities(useExpression)], + references: [refA], + parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), + options: TestOptions.ReleaseExe); + if (languageVersion == LanguageVersion.CSharp13 && useExpression) + { + comp.VerifyEmitDiagnostics( + // (5,28): error CS0853: An expression tree may not contain a named argument specification + // Utils.Report(() => A.GetFirst(first: default, default)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, "A.GetFirst(first: default, default)").WithLocation(5, 28), + // (6,28): error CS0853: An expression tree may not contain a named argument specification + // Utils.Report(() => A.GetFirst(second: default, default)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, "A.GetFirst(second: default, default)").WithLocation(6, 28), + // (7,28): error CS0853: An expression tree may not contain a named argument specification + // Utils.Report(() => A.GetFirst(default, second: default)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, "A.GetFirst(default, second: default)").WithLocation(7, 28), + // (8,28): error CS0853: An expression tree may not contain a named argument specification + // Utils.Report(() => A.GetFirst(default, first: default)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, "A.GetFirst(default, first: default)").WithLocation(8, 28)); + } + else if (useExpression) + { + comp.VerifyEmitDiagnostics(); + } + else + { + var verifier = CompileAndVerify( + comp, + expectedOutput: """ + --: 0 + --: null + --: 0 + --: null + """); + verifier.VerifyDiagnostics(); + } + + string sourceB4 = $$""" + class Program + { + static void Main() + { + Utils.Report(() => A.GetFirst(first: default, second: default)); + Utils.Report(() => A.GetFirst(second: default, first: default)); + } + } + """; + comp = CreateCompilation( + [sourceB4, GetUtilities(useExpression)], + references: [refA], + parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), + options: TestOptions.ReleaseExe); + comp.VerifyEmitDiagnostics( + // (5,30): error CS0121: The call is ambiguous between the following methods or properties: 'A.GetFirst(int, int)' and 'A.GetFirst(string, string)' + // Utils.Report(() => A.GetFirst(first: default, second: default)); + Diagnostic(ErrorCode.ERR_AmbigCall, "GetFirst").WithArguments("A.GetFirst(int, int)", "A.GetFirst(string, string)").WithLocation(5, 30), + // (6,30): error CS0121: The call is ambiguous between the following methods or properties: 'A.GetFirst(int, int)' and 'A.GetFirst(string, string)' + // Utils.Report(() => A.GetFirst(second: default, first: default)); + Diagnostic(ErrorCode.ERR_AmbigCall, "GetFirst").WithArguments("A.GetFirst(int, int)", "A.GetFirst(string, string)").WithLocation(6, 30)); + } + + [Theory] + [CombinatorialData] + public void NamedArgument_Constructor( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersion.Preview, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion, + bool useExpression) + { + string sourceA = $$""" + public class A + { + public readonly string X; + public readonly int Y; + public A(string x, ref int y) { X = x; Y = y; } + public override string ToString() => $"({X}, {Y})"; + } + """; + var comp = CreateCompilation(sourceA); + var refA = comp.EmitToImageReference(); + + string sourceB1 = $$""" + class Program + { + static void Main() + { + int y = 1; + Utils.Report(() => new A(x: "one", ref y)); + y = 2; + Utils.Report(() => new A("two", y: ref y)); + y = 3; + Utils.Report(() => new A(x: "three", y: ref y)); + } + } + """; + comp = CreateCompilation( + [sourceB1, GetUtilities(useExpression)], + references: [refA], + parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), + options: TestOptions.ReleaseExe); + if (languageVersion == LanguageVersion.CSharp13 && useExpression) + { + comp.VerifyEmitDiagnostics( + // (6,28): error CS0853: An expression tree may not contain a named argument specification + // Utils.Report(() => new A(x: "one", ref y)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, @"new A(x: ""one"", ref y)").WithLocation(6, 28), + // (8,28): error CS0853: An expression tree may not contain a named argument specification + // Utils.Report(() => new A("two", y: ref y)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, @"new A(""two"", y: ref y)").WithLocation(8, 28), + // (10,28): error CS0853: An expression tree may not contain a named argument specification + // Utils.Report(() => new A(x: "three", y: ref y)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, @"new A(x: ""three"", y: ref y)").WithLocation(10, 28)); + } + else + { + var verifier = CompileAndVerify( + comp, + expectedOutput: IncludeExpression(useExpression, """ + () => new A("one", value(Program+<>c__DisplayClass0_0).y): (one, 1) + () => new A("two", value(Program+<>c__DisplayClass0_0).y): (two, 2) + () => new A("three", value(Program+<>c__DisplayClass0_0).y): (three, 3) + """)); + verifier.VerifyDiagnostics(); + } + + string sourceB2 = $$""" + class Program + { + static void Main() + { + int y = 1; + Utils.Report(() => new A(y: ref y, x: "one")); + } + } + """; + comp = CreateCompilation( + [sourceB2, GetUtilities(useExpression)], + references: [refA], + parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), + options: TestOptions.ReleaseExe); + if (languageVersion == LanguageVersion.CSharp13 && useExpression) + { + comp.VerifyEmitDiagnostics( + // (6,28): error CS0853: An expression tree may not contain a named argument specification + // Utils.Report(() => new A(y: ref y, x: "one")); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, @"new A(y: ref y, x: ""one"")").WithLocation(6, 28)); + } + else if (useExpression) + { + comp.VerifyEmitDiagnostics( + // (6,28): error CS9307: An expression tree may not contain a named argument specification out of position + // Utils.Report(() => new A(y: ref y, x: "one")); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgumentOutOfPosition, @"new A(y: ref y, x: ""one"")").WithLocation(6, 28)); + } + else + { + var verifier = CompileAndVerify( + comp, + expectedOutput: """ + --: (one, 1) + """); + verifier.VerifyDiagnostics(); + } + } + + [Theory] + [CombinatorialData] + public void NamedArgument_Indexer( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersion.Preview, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion, + bool useExpression) + { + string sourceA = $$""" + public class A + { + public string this[int x, in string y] => y; + } + """; + var comp = CreateCompilation(sourceA); + var refA = comp.EmitToImageReference(); + + string sourceB1 = $$""" + class Program + { + static void Main() + { + var a = new A(); + string y = "one"; + Utils.Report(() => a[x: 1, in y]); + Utils.Report(() => a[2, y: "two"]); + y = "three"; + Utils.Report(() => a[x: 2, y: in y]); + } + } + """; + comp = CreateCompilation( + [sourceB1, GetUtilities(useExpression)], + references: [refA], + parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), + options: TestOptions.ReleaseExe); + if (languageVersion == LanguageVersion.CSharp13 && useExpression) + { + comp.VerifyEmitDiagnostics( + // (7,28): error CS0853: An expression tree may not contain a named argument specification + // Utils.Report(() => a[x: 1, in y]); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, "a[x: 1, in y]").WithLocation(7, 28), + // (8,28): error CS0853: An expression tree may not contain a named argument specification + // Utils.Report(() => a[2, y: "two"]); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, @"a[2, y: ""two""]").WithLocation(8, 28), + // (10,28): error CS0853: An expression tree may not contain a named argument specification + // Utils.Report(() => a[x: 2, y: in y]); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, "a[x: 2, y: in y]").WithLocation(10, 28)); + } + else + { + var verifier = CompileAndVerify( + comp, + expectedOutput: IncludeExpression(useExpression, """ + () => value(Program+<>c__DisplayClass0_0).a.get_Item(1, value(Program+<>c__DisplayClass0_0).y): one + () => value(Program+<>c__DisplayClass0_0).a.get_Item(2, "two"): two + () => value(Program+<>c__DisplayClass0_0).a.get_Item(2, value(Program+<>c__DisplayClass0_0).y): three + """)); + verifier.VerifyDiagnostics(); + } + + string sourceB2 = $$""" + class Program + { + static void Main() + { + var a = new A(); + string y = "two"; + Utils.Report(() => a[y: "one", x: 1]); + Utils.Report(() => a[y: in y, x: 2]); + } + } + """; + comp = CreateCompilation( + [sourceB2, GetUtilities(useExpression)], + references: [refA], + parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), + options: TestOptions.ReleaseExe); + if (languageVersion == LanguageVersion.CSharp13 && useExpression) + { + comp.VerifyEmitDiagnostics( + // (7,28): error CS0853: An expression tree may not contain a named argument specification + // Utils.Report(() => a[y: "one", x: 1]); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, @"a[y: ""one"", x: 1]").WithLocation(7, 28), + // (8,28): error CS0853: An expression tree may not contain a named argument specification + // Utils.Report(() => a[y: in y, x: 2]); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, "a[y: in y, x: 2]").WithLocation(8, 28)); + } + else if (useExpression) + { + comp.VerifyEmitDiagnostics( + // (7,28): error CS9307: An expression tree may not contain a named argument specification out of position + // Utils.Report(() => a[y: "one", x: 1]); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgumentOutOfPosition, @"a[y: ""one"", x: 1]").WithLocation(7, 28), + // (8,28): error CS9307: An expression tree may not contain a named argument specification out of position + // Utils.Report(() => a[y: in y, x: 2]); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgumentOutOfPosition, "a[y: in y, x: 2]").WithLocation(8, 28)); + } + else + { + var verifier = CompileAndVerify( + comp, + expectedOutput: """ + --: one + --: two + """); + verifier.VerifyDiagnostics(); + } + } + + [Theory] + [CombinatorialData] + public void NamedArgument_Delegate( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersion.Preview, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion, + bool useExpression) + { + string sourceA = $$""" + public delegate (T, U) D(T x, U y); + """; + var comp = CreateCompilation(sourceA); + var refA = comp.EmitToImageReference(); + + string sourceB1 = $$""" + class Program + { + static void Main() + { + D d = F; + Utils.Report(() => d(x: 1, "one")); + Utils.Report(() => d(2, y: "two")); + Utils.Report(() => d(x: 3, y: "three")); + } + static (int, string) F(int i, string s) => (i, s); + } + """; + comp = CreateCompilation( + [sourceB1, GetUtilities(useExpression)], + references: [refA], + parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), + options: TestOptions.ReleaseExe); + if (languageVersion == LanguageVersion.CSharp13 && useExpression) + { + comp.VerifyEmitDiagnostics( + // (6,28): error CS0853: An expression tree may not contain a named argument specification + // Utils.Report(() => d(x: 1, "one")); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, @"d(x: 1, ""one"")").WithLocation(6, 28), + // (7,28): error CS0853: An expression tree may not contain a named argument specification + // Utils.Report(() => d(2, y: "two")); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, @"d(2, y: ""two"")").WithLocation(7, 28), + // (8,28): error CS0853: An expression tree may not contain a named argument specification + // Utils.Report(() => d(x: 3, y: "three")); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, @"d(x: 3, y: ""three"")").WithLocation(8, 28)); + } + else + { + var verifier = CompileAndVerify( + comp, + expectedOutput: IncludeExpression(useExpression, """ + () => Invoke(value(Program+<>c__DisplayClass0_0).d, 1, "one"): (1, one) + () => Invoke(value(Program+<>c__DisplayClass0_0).d, 2, "two"): (2, two) + () => Invoke(value(Program+<>c__DisplayClass0_0).d, 3, "three"): (3, three) + """)); + verifier.VerifyDiagnostics(); + } + + string sourceB2 = $$""" + class Program + { + static void Main() + { + D d = F; + Utils.Report(() => d(y:"one", x:1)); + } + static (int, string) F(int i, string s) => (i, s); + } + """; + comp = CreateCompilation( + [sourceB2, GetUtilities(useExpression)], + references: [refA], + parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), + options: TestOptions.ReleaseExe); + if (languageVersion == LanguageVersion.CSharp13 && useExpression) + { + comp.VerifyEmitDiagnostics( + // (6,28): error CS0853: An expression tree may not contain a named argument specification + // Utils.Report(() => d(y:"one", x:1)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, @"d(y:""one"", x:1)").WithLocation(6, 28)); + } + else if (useExpression) + { + comp.VerifyEmitDiagnostics( + // (6,28): error CS9307: An expression tree may not contain a named argument specification out of position + // Utils.Report(() => d(y:"one", x:1)); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgumentOutOfPosition, @"d(y:""one"", x:1)").WithLocation(6, 28)); + } + else + { + var verifier = CompileAndVerify( + comp, + expectedOutput: """ + --: (1, one) + """); + verifier.VerifyDiagnostics(); + } + } + + [Theory] + [CombinatorialData] + public void NamedArgument_LocalFunction( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersion.Preview, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion) + { + string source = """ + using System; + using System.Linq.Expressions; + class Program + { + static void Main() + { + Expression> e; + T GetFirst(T first, T second) => first; + GetFirst(first: 1, 2); + GetFirst(1, second: 2); + GetFirst(second: 2, first: 1); + e = () => GetFirst(first: 1, 2); + e = () => GetFirst(1, second: 2); + e = () => GetFirst(second: 2, first: 1); + } + } + """; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + if (languageVersion == LanguageVersion.CSharp13) + { + comp.VerifyEmitDiagnostics( + // (12,19): error CS0853: An expression tree may not contain a named argument specification + // e = () => GetFirst(first: 1, 2); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, "GetFirst(first: 1, 2)").WithLocation(12, 19), + // (13,19): error CS0853: An expression tree may not contain a named argument specification + // e = () => GetFirst(1, second: 2); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, "GetFirst(1, second: 2)").WithLocation(13, 19), + // (14,19): error CS0853: An expression tree may not contain a named argument specification + // e = () => GetFirst(second: 2, first: 1); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, "GetFirst(second: 2, first: 1)").WithLocation(14, 19)); + } + else + { + comp.VerifyEmitDiagnostics( + // (12,19): error CS8110: An expression tree may not contain a reference to a local function + // e = () => GetFirst(first: 1, 2); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsLocalFunction, "GetFirst(first: 1, 2)").WithLocation(12, 19), + // (13,19): error CS8110: An expression tree may not contain a reference to a local function + // e = () => GetFirst(1, second: 2); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsLocalFunction, "GetFirst(1, second: 2)").WithLocation(13, 19), + // (14,19): error CS9307: An expression tree may not contain a named argument specification out of position + // e = () => GetFirst(second: 2, first: 1); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgumentOutOfPosition, "GetFirst(second: 2, first: 1)").WithLocation(14, 19)); + } + } + } +} diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/SemanticErrorTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/SemanticErrorTests.cs index c3a4b47e22d63..759e12b5e3d76 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/SemanticErrorTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/SemanticErrorTests.cs @@ -13082,8 +13082,9 @@ public static void Main(string[] args) Diagnostic(ErrorCode.ERR_ArrayInitializerIncorrectLength, "{}").WithArguments("3").WithLocation(7, 31)); } - [Fact] - public void CS0853ERR_ExpressionTreeContainsNamedArgument01() + [Theory] + [MemberData(nameof(LanguageVersions13AndNewer))] + public void CS0853ERR_ExpressionTreeContainsNamedArgument01(LanguageVersion languageVersion) { var text = @" using System.Linq.Expressions; @@ -13095,6 +13096,7 @@ class Program static void Main(string[] args) { Expression myET = x => Index(minSessions:5); + System.Console.WriteLine(myET); } public static string Index(int minSessions = 0) { @@ -13103,16 +13105,26 @@ public static string Index(int minSessions = 0) } } "; - CreateCompilationWithMscorlib40AndSystemCore(text).VerifyDiagnostics( - // (10,40): error CS0853: An expression tree may not contain a named argument specification - // Expression myET = x => Index(minSessions:5); - Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, "Index(minSessions:5)").WithLocation(10, 40) - ); + var comp = CreateCompilationWithMscorlib40AndSystemCore(text, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), options: TestOptions.ReleaseExe); + if (languageVersion == LanguageVersion.CSharp13) + { + comp.VerifyDiagnostics( + // (10,40): error CS0853: An expression tree may not contain a named argument specification + // Expression myET = x => Index(minSessions:5); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, "Index(minSessions:5)").WithLocation(10, 40) + ); + } + else + { + var verifier = CompileAndVerify(comp, expectedOutput: "x => Index(5)"); + verifier.VerifyDiagnostics(); + } } [WorkItem(545063, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545063")] - [Fact] - public void CS0853ERR_ExpressionTreeContainsNamedArgument02() + [Theory] + [MemberData(nameof(LanguageVersions13AndNewer))] + public void CS0853ERR_ExpressionTreeContainsNamedArgument02(LanguageVersion languageVersion) { var text = @" using System; @@ -13124,18 +13136,29 @@ class A static void Main() { Expression> f = () => new List { 1 } [index: 0]; + Console.WriteLine(f); } } "; - CreateCompilationWithMscorlib40AndSystemCore(text).VerifyDiagnostics( - // (10,41): error CS0853: An expression tree may not contain a named argument specification - // Expression> f = () => new List { 1 } [index: 0]; - Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, "new List { 1 } [index: 0]").WithLocation(10, 41) - ); + var comp = CreateCompilationWithMscorlib40AndSystemCore(text, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), options: TestOptions.ReleaseExe); + if (languageVersion == LanguageVersion.CSharp13) + { + comp.VerifyDiagnostics( + // (10,41): error CS0853: An expression tree may not contain a named argument specification + // Expression> f = () => new List { 1 } [index: 0]; + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsNamedArgument, "new List { 1 } [index: 0]").WithLocation(10, 41) + ); + } + else + { + var verifier = CompileAndVerify(comp, expectedOutput: "() => new List`1() {Void Add(Int32)(1)}.get_Item(0)"); + verifier.VerifyDiagnostics(); + } } - [Fact] - public void CS0854ERR_ExpressionTreeContainsOptionalArgument01() + [Theory] + [MemberData(nameof(LanguageVersions13AndNewer))] + public void CS0854ERR_ExpressionTreeContainsOptionalArgument01(LanguageVersion languageVersion) { var text = @" using System.Linq.Expressions; @@ -13147,6 +13170,7 @@ class Program static void Main(string[] args) { Expression myET = x => Index(); + System.Console.WriteLine(myET); } public static string Index(int minSessions = 0) { @@ -13155,15 +13179,25 @@ public static string Index(int minSessions = 0) } } "; - CreateCompilationWithMscorlib40AndSystemCore(text).VerifyDiagnostics( - // (10,40): error CS0854: An expression tree may not contain a call or invocation that uses optional arguments - // Expression myET = x => Index(); - Diagnostic(ErrorCode.ERR_ExpressionTreeContainsOptionalArgument, "Index()").WithLocation(10, 40) - ); + var comp = CreateCompilationWithMscorlib40AndSystemCore(text, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), options: TestOptions.ReleaseExe); + if (languageVersion == LanguageVersion.CSharp13) + { + comp.VerifyDiagnostics( + // (10,40): error CS0854: An expression tree may not contain a call or invocation that uses optional arguments + // Expression myET = x => Index(); + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsOptionalArgument, "Index()").WithLocation(10, 40) + ); + } + else + { + var verifier = CompileAndVerify(comp, expectedOutput: "x => Index(0)"); + verifier.VerifyDiagnostics(); + } } - [Fact] - public void CS0854ERR_ExpressionTreeContainsOptionalArgument02() + [Theory] + [MemberData(nameof(LanguageVersions13AndNewer))] + public void CS0854ERR_ExpressionTreeContainsOptionalArgument02(LanguageVersion languageVersion) { var text = @"using System; @@ -13194,19 +13228,38 @@ static void M(A a, B b) e2 = () => b[4, 5] = null; } }"; - CreateCompilationWithMscorlib40AndSystemCore(text).VerifyDiagnostics( - // (22,20): error CS0854: An expression tree may not contain a call or invocation that uses optional arguments - Diagnostic(ErrorCode.ERR_ExpressionTreeContainsOptionalArgument, "a[0]").WithLocation(22, 20), - // (25,20): error CS0832: An expression tree may not contain an assignment operator - Diagnostic(ErrorCode.ERR_ExpressionTreeContainsAssignment, "b[3] = null").WithLocation(25, 20), - // (25,20): error CS0854: An expression tree may not contain a call or invocation that uses optional arguments - Diagnostic(ErrorCode.ERR_ExpressionTreeContainsOptionalArgument, "b[3]").WithLocation(25, 20), - // (26,20): error CS0832: An expression tree may not contain an assignment operator - Diagnostic(ErrorCode.ERR_ExpressionTreeContainsAssignment, "b[4, 5] = null").WithLocation(26, 20)); + var comp = CreateCompilationWithMscorlib40AndSystemCore(text, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + if (languageVersion == LanguageVersion.CSharp13) + { + comp.VerifyDiagnostics( + // (22,20): error CS0854: An expression tree may not contain a call or invocation that uses optional arguments + // e1 = () => a[0]; + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsOptionalArgument, "a[0]").WithLocation(22, 20), + // (25,20): error CS0832: An expression tree may not contain an assignment operator + // e2 = () => b[3] = null; + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsAssignment, "b[3] = null").WithLocation(25, 20), + // (25,20): error CS0854: An expression tree may not contain a call or invocation that uses optional arguments + // e2 = () => b[3] = null; + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsOptionalArgument, "b[3]").WithLocation(25, 20), + // (26,20): error CS0832: An expression tree may not contain an assignment operator + // e2 = () => b[4, 5] = null; + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsAssignment, "b[4, 5] = null").WithLocation(26, 20)); + } + else + { + comp.VerifyDiagnostics( + // (25,20): error CS0832: An expression tree may not contain an assignment operator + // e2 = () => b[3] = null; + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsAssignment, "b[3] = null").WithLocation(25, 20), + // (26,20): error CS0832: An expression tree may not contain an assignment operator + // e2 = () => b[4, 5] = null; + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsAssignment, "b[4, 5] = null").WithLocation(26, 20)); + } } - [Fact] - public void CS0854ERR_ExpressionTreeContainsOptionalArgument03() + [Theory] + [MemberData(nameof(LanguageVersions13AndNewer))] + public void CS0854ERR_ExpressionTreeContainsOptionalArgument03(LanguageVersion languageVersion) { var text = @"using System; @@ -13224,15 +13277,25 @@ public IEnumerator GetEnumerator() } public class C { - public void M() { + static void Main() { Expression> expr = () => new Collection { 1 }; // 1 + Console.WriteLine(expr); } }"; - CreateCompilation(text).VerifyDiagnostics( - // (18,36): error CS0854: An expression tree may not contain a call or invocation that uses optional arguments - // () => new Collection { 1 }; // 1 - Diagnostic(ErrorCode.ERR_ExpressionTreeContainsOptionalArgument, "1").WithLocation(18, 36)); + var comp = CreateCompilation(text, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), options: TestOptions.ReleaseExe); + if (languageVersion == LanguageVersion.CSharp13) + { + comp.VerifyDiagnostics( + // (18,36): error CS0854: An expression tree may not contain a call or invocation that uses optional arguments + // () => new Collection { 1 }; // 1 + Diagnostic(ErrorCode.ERR_ExpressionTreeContainsOptionalArgument, "1").WithLocation(18, 36)); + } + else + { + var verifier = CompileAndVerify(comp, expectedOutput: "() => new Collection() {Void Add(Int32, Int32)(1, 0)}"); + verifier.VerifyDiagnostics(); + } } [Fact] diff --git a/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs b/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs index cabe8fa772230..671bb494774e3 100644 --- a/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs +++ b/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs @@ -37,6 +37,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Test.Utilities { public abstract class CSharpTestBase : CommonTestBase { + public static readonly TheoryData LanguageVersions13AndNewer = new TheoryData([LanguageVersion.CSharp13, LanguageVersion.Preview, LanguageVersionFacts.CSharpNext]); + protected static readonly string NullableAttributeDefinition = @" namespace System.Runtime.CompilerServices {