File: Semantics\NonTrailingNamedArgumentsTests.cs
Web Access
Project: src\src\Compilers\CSharp\Test\Semantic\Microsoft.CodeAnalysis.CSharp.Semantic.UnitTests.csproj (Microsoft.CodeAnalysis.CSharp.Semantic.UnitTests)
// 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 System.Linq;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
using Basic.Reference.Assemblies;
 
namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Semantics
{
    [CompilerTrait(CompilerFeature.NonTrailingNamedArgs)]
    public class NonTrailingNamedArgumentsTests : CompilingTestBase
    {
        [Fact]
        public void TestSimple()
        {
            var source = @"
class C
{
    static void M(int a, int b)
    {
        System.Console.Write($""First {a} {b}. "");
    }
    static void M(long b, long a)
    {
        System.Console.Write($""Second {b} {a}. "");
    }
    static void Main()
    {
        M(a: 1, 2);
        M(3, a: 4);
    }
}";
            var verifier = CompileAndVerify(source, expectedOutput: "First 1 2. Second 3 4.", parseOptions: TestOptions.Regular7_2);
            verifier.VerifyDiagnostics();
 
            var tree = verifier.Compilation.SyntaxTrees.First();
            var model = verifier.Compilation.GetSemanticModel(tree);
            var nodes = tree.GetCompilationUnitRoot().DescendantNodes();
            var firstInvocation = nodes.OfType<InvocationExpressionSyntax>().ElementAt(2);
            Assert.Equal("M(a: 1, 2)", firstInvocation.ToString());
            Assert.Equal("void C.M(System.Int32 a, System.Int32 b)",
                model.GetSymbolInfo(firstInvocation).Symbol.ToTestDisplayString());
 
            var firstNamedArgA = nodes.OfType<NameColonSyntax>().ElementAt(0);
            Assert.Equal("a: 1", firstNamedArgA.Parent.ToString());
            var firstASymbol = model.GetSymbolInfo(firstNamedArgA.Name);
            Assert.Equal(SymbolKind.Parameter, firstASymbol.Symbol.Kind);
            Assert.Equal("a", firstASymbol.Symbol.Name);
            Assert.Equal("void C.M(System.Int32 a, System.Int32 b)", firstASymbol.Symbol.ContainingSymbol.ToTestDisplayString());
 
            var secondInvocation = nodes.OfType<InvocationExpressionSyntax>().ElementAt(3);
            Assert.Equal("M(3, a: 4)", secondInvocation.ToString());
            Assert.Equal("void C.M(System.Int64 b, System.Int64 a)",
                model.GetSymbolInfo(secondInvocation).Symbol.ToTestDisplayString());
 
            var secondNamedArgA = nodes.OfType<NameColonSyntax>().ElementAt(1);
            Assert.Equal("a: 4", secondNamedArgA.Parent.ToString());
            var secondASymbol = model.GetSymbolInfo(secondNamedArgA.Name);
            Assert.Equal(SymbolKind.Parameter, secondASymbol.Symbol.Kind);
            Assert.Equal("a", secondASymbol.Symbol.Name);
            Assert.Equal("void C.M(System.Int64 b, System.Int64 a)", secondASymbol.Symbol.ContainingSymbol.ToTestDisplayString());
        }
 
        [Fact]
        public void TestSimpleConstructor()
        {
            var source = @"
class C
{
    C(int a, int b)
    {
        System.Console.Write($""{a} {b}."");
    }
    static void Main()
    {
        new C(a: 1, 2);
    }
}";
            var verifier = CompileAndVerify(source, expectedOutput: "1 2.", parseOptions: TestOptions.Regular7_2);
            verifier.VerifyDiagnostics();
 
            var comp = CreateCompilation(source, parseOptions: TestOptions.Regular7_1);
            comp.VerifyDiagnostics(
                // (10,21): error CS1738: Named argument specifications must appear after all fixed arguments have been specified. Please use language version 7.2 or greater to allow non-trailing named arguments.
                //         new C(a: 1, 2);
                Diagnostic(ErrorCode.ERR_NamedArgumentSpecificationBeforeFixedArgument, "2").WithArguments("7.2").WithLocation(10, 21)
                );
        }
 
        [Fact]
        public void TestSimpleThis()
        {
            var source = @"
class C
{
    C(int a, int b)
    {
        System.Console.Write($""{a} {b}."");
    }
    C() : this(a: 1, 2) { }
 
    static void Main()
    {
        new C();
    }
}";
            var verifier = CompileAndVerify(source, expectedOutput: "1 2.", parseOptions: TestOptions.Regular7_2);
            verifier.VerifyDiagnostics();
        }
 
        [Fact]
        public void TestSimpleBase()
        {
            var source = @"
public class C
{
    public C(int a, int b)
    {
        System.Console.Write($""{a} {b}."");
    }
}
class Derived : C
{
    Derived() : base(a: 1, 2) { }
 
    static void Main()
    {
        new Derived();
    }
}";
            var verifier = CompileAndVerify(source, expectedOutput: "1 2.", parseOptions: TestOptions.Regular7_2);
            verifier.VerifyDiagnostics();
        }
 
        [Fact]
        public void TestSimpleExtension()
        {
            var source = @"
public static class Extension
{
    public static void M(this C c, int a, int b)
    {
        System.Console.Write($""{a} {b}."");
    }
}
public class C
{
    static void Main()
    {
        var c = new C();
        c.M(a: 1, 2);
    }
}";
            var verifier = CompileAndVerifyWithMscorlib40(source, expectedOutput: "1 2.", parseOptions: TestOptions.Regular7_2, references: new[] { Net40.References.SystemCore });
            verifier.VerifyDiagnostics();
 
            var comp = CreateCompilationWithMscorlib40(source, parseOptions: TestOptions.Regular7_1, references: new[] { Net40.References.SystemCore });
            comp.VerifyDiagnostics(
                // (14,19): error CS1738: Named argument specifications must appear after all fixed arguments have been specified. Please use language version 7.2 or greater to allow non-trailing named arguments.
                //         c.M(a: 1, 2);
                Diagnostic(ErrorCode.ERR_NamedArgumentSpecificationBeforeFixedArgument, "2").WithArguments("7.2").WithLocation(14, 19)
                );
        }
 
        [Fact]
        public void TestSimpleDelegate()
        {
            var source = @"
class C
{
    delegate void MyDelegate(int a, int b);
    event MyDelegate e;
 
    static void M(int a, int b)
    {
        System.Console.Write($""{a} {b}. "");
    }
 
    static void Main()
    {
        var c = new C();
        c.e += M;
        c.e.Invoke(a: 1, 2);
        c.e(a: 1, 2);
    }
}";
            var verifier = CompileAndVerify(source, expectedOutput: "1 2. 1 2.", parseOptions: TestOptions.Regular7_2);
            verifier.VerifyDiagnostics();
 
            var comp = CreateCompilation(source, parseOptions: TestOptions.Regular7_1);
            comp.VerifyDiagnostics(
                // (16,26): error CS1738: Named argument specifications must appear after all fixed arguments have been specified. Please use language version 7.2 or greater to allow non-trailing named arguments.
                //         c.e.Invoke(a: 1, 2);
                Diagnostic(ErrorCode.ERR_NamedArgumentSpecificationBeforeFixedArgument, "2").WithArguments("7.2").WithLocation(16, 26),
                // (17,19): error CS1738: Named argument specifications must appear after all fixed arguments have been specified. Please use language version 7.2 or greater to allow non-trailing named arguments.
                //         c.e(a: 1, 2);
                Diagnostic(ErrorCode.ERR_NamedArgumentSpecificationBeforeFixedArgument, "2").WithArguments("7.2").WithLocation(17, 19)
                );
        }
 
        [Fact]
        public void TestSimpleLocalFunction()
        {
            var source = @"
class C
{
    static void Main()
    {
        var c = new C();
        local(a: 1, 2);
 
        void local(int a, int b)
        {
            System.Console.Write($""{a} {b}."");
        }
    }
}";
            var verifier = CompileAndVerify(source, expectedOutput: "1 2.", parseOptions: TestOptions.Regular7_2);
            verifier.VerifyDiagnostics();
 
            var comp = CreateCompilation(source, parseOptions: TestOptions.Regular7_1);
            comp.VerifyDiagnostics(
                // (7,21): error CS1738: Named argument specifications must appear after all fixed arguments have been specified. Please use language version 7.2 or greater to allow non-trailing named arguments.
                //         local(a: 1, 2);
                Diagnostic(ErrorCode.ERR_NamedArgumentSpecificationBeforeFixedArgument, "2").WithArguments("7.2").WithLocation(7, 21)
                );
        }
 
        [Fact]
        public void TestSimpleIndexer()
        {
            var source = @"
class C
{
    int this[int a, int b]
    {
        get
        {
            System.Console.Write($""Get {a} {b}. "");
            return 0;
        }
        set
        {
            System.Console.Write($""Set {a} {b} {value}."");
        }
    }
    static void Main()
    {
        var c = new C();
        _ = c[a: 1, 2];
        c[a: 3, 4] = 5;
    }
}";
            var verifier = CompileAndVerify(source, expectedOutput: "Get 1 2. Set 3 4 5.", parseOptions: TestOptions.Regular7_2);
            verifier.VerifyDiagnostics();
 
            var comp = CreateCompilation(source, parseOptions: TestOptions.Regular7_1);
            comp.VerifyDiagnostics(
                // (19,21): error CS1738: Named argument specifications must appear after all fixed arguments have been specified. Please use language version 7.2 or greater to allow non-trailing named arguments.
                //         _ = c[a: 1, 2];
                Diagnostic(ErrorCode.ERR_NamedArgumentSpecificationBeforeFixedArgument, "2").WithArguments("7.2").WithLocation(19, 21),
                // (20,17): error CS1738: Named argument specifications must appear after all fixed arguments have been specified. Please use language version 7.2 or greater to allow non-trailing named arguments.
                //         c[a: 3, 4] = 5;
                Diagnostic(ErrorCode.ERR_NamedArgumentSpecificationBeforeFixedArgument, "4").WithArguments("7.2").WithLocation(20, 17)
                );
        }
 
        [Fact]
        public void TestSimpleError()
        {
            var source = @"
class C
{
    int this[int a, int b]
    {
        get
        {
            throw null;
        }
    }
 
    C(int a, int b) { }
 
    static void Main()
    {
        var c = new C(b: 1, 2);
        _ = c[b: 1, 2];
        local(b: 1, 2);
 
        void local(int a, int b) { }
    }
}";
            var comp = CreateCompilation(source, parseOptions: TestOptions.Regular7_2);
            comp.VerifyDiagnostics(
                // (16,23): error CS8322: Named argument 'b' is used out-of-position but is followed by an unnamed argument
                //         var c = new C(b: 1, 2);
                Diagnostic(ErrorCode.ERR_BadNonTrailingNamedArgument, "b").WithArguments("b").WithLocation(16, 23),
                // (17,15): error CS8322: Named argument 'b' is used out-of-position but is followed by an unnamed argument
                //         _ = c[b: 1, 2];
                Diagnostic(ErrorCode.ERR_BadNonTrailingNamedArgument, "b").WithArguments("b").WithLocation(17, 15),
                // (18,15): error CS8322: Named argument 'b' is used out-of-position but is followed by an unnamed argument
                //         local(b: 1, 2);
                Diagnostic(ErrorCode.ERR_BadNonTrailingNamedArgument, "b").WithArguments("b").WithLocation(18, 15)
                );
        }
 
        [Fact]
        public void TestMetadataAndPESymbols()
        {
            var lib_cs = @"
public class C
{
    public static void M(int a, int b)
    {
        System.Console.Write($""{a} {b}."");
    }
}";
 
            var source = @"
class D
{
    static void Main()
    {
        C.M(a: 1, 2);
    }
}";
            var lib = CreateCompilation(lib_cs, parseOptions: TestOptions.Regular7);
 
            var verifier1 = CompileAndVerify(source, expectedOutput: "1 2.", parseOptions: TestOptions.Regular7_2, references: new[] { lib.ToMetadataReference() });
            verifier1.VerifyDiagnostics();
 
            var verifier2 = CompileAndVerify(source, expectedOutput: "1 2.", parseOptions: TestOptions.Regular7_2, references: new[] { lib.EmitToImageReference() });
            verifier2.VerifyDiagnostics();
        }
 
        [Fact]
        public void TestPositionalUnaffected()
        {
            var source = @"
class C
{
    static void M(int first, int other)
    {
        System.Console.Write($""{first} {other}"");
    }
    static void Main()
    {
        M(1, first: 2);
    }
}";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics(
                // (10,14): error CS1744: Named argument 'first' specifies a parameter for which a positional argument has already been given
                //         M(1, first: 2);
                Diagnostic(ErrorCode.ERR_NamedArgumentUsedInPositional, "first").WithArguments("first").WithLocation(10, 14)
                );
 
            var tree = comp.SyntaxTrees.First();
            var model = comp.GetSemanticModel(tree);
            var nodes = tree.GetCompilationUnitRoot().DescendantNodes();
            var invocation = nodes.OfType<InvocationExpressionSyntax>().ElementAt(1);
            Assert.Equal("M(1, first: 2)", invocation.ToString());
            Assert.Null(model.GetSymbolInfo(invocation).Symbol);
        }
 
        [Fact]
        public void TestGenericInference()
        {
            var source = @"
class C
{
    static void M<T1, T2>(T1 a, T2 b)
    {
        System.Console.Write($""{a} {b}."");
    }
    static void Main()
    {
        C.M(a: 1, ""hi"");
    }
}";
            var verifier = CompileAndVerify(source, expectedOutput: "1 hi.", parseOptions: TestOptions.Regular7_2);
            verifier.VerifyDiagnostics();
 
            var tree = verifier.Compilation.SyntaxTrees.First();
            var model = verifier.Compilation.GetSemanticModel(tree);
            var nodes = tree.GetCompilationUnitRoot().DescendantNodes();
            var invocation = nodes.OfType<InvocationExpressionSyntax>().ElementAt(1);
            Assert.Equal(@"C.M(a: 1, ""hi"")", invocation.ToString());
            Assert.Equal("void C.M<System.Int32, System.String>(System.Int32 a, System.String b)", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString());
        }
 
        [Fact]
        public void TestPositionalUnaffected2()
        {
            var source = @"
class C
{
    static void M(int a, int b, int c = 1)
    {
        System.Console.Write($""M {a} {b}"");
    }
    static void Main()
    {
        M(c: 1, 2);
    }
}";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics(
                // (10,11): error CS8321: Named argument 'c' is used out-of-position but is followed by an unnamed argument
                //         M(c: 1, 2);
                Diagnostic(ErrorCode.ERR_BadNonTrailingNamedArgument, "c").WithArguments("c").WithLocation(10, 11)
                );
 
            var tree = comp.SyntaxTrees.First();
            var model = comp.GetSemanticModel(tree);
            var nodes = tree.GetCompilationUnitRoot().DescendantNodes();
            var invocation = nodes.OfType<InvocationExpressionSyntax>().ElementAt(1);
            Assert.Equal("M(c: 1, 2)", invocation.ToString());
            SymbolInfo symbol = model.GetSymbolInfo(invocation);
            AssertEx.Equal(new[] { "void C.M(System.Int32 a, System.Int32 b, [System.Int32 c = 1])" },
                symbol.CandidateSymbols.Select(c => c.ToTestDisplayString()));
            Assert.Equal(CandidateReason.OverloadResolutionFailure, symbol.CandidateReason);
        }
 
        [Fact]
        public void TestNamedParams()
        {
            var source = @"
class C
{
    static void M(params int[] x)
    {
    }
    static void Main()
    {
        M(x: 1, 2);
    }
}";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics(
                // (9,9): error CS1501: No overload for method 'M' takes 2 arguments
                //         M(x: 1, 2);
                Diagnostic(ErrorCode.ERR_BadArgCount, "M").WithArguments("M", "2").WithLocation(9, 9)
                );
 
            var tree = comp.SyntaxTrees.First();
            var model = comp.GetSemanticModel(tree);
            var nodes = tree.GetCompilationUnitRoot().DescendantNodes();
            var invocation = nodes.OfType<InvocationExpressionSyntax>().Single();
            Assert.Equal("M(x: 1, 2)", invocation.ToString());
            Assert.Null(model.GetSymbolInfo(invocation).Symbol);
        }
 
        [Fact]
        public void TestNamedParams2()
        {
            var source = @"
class C
{
    static void M(params int[] x)
    {
    }
    static void Main()
    {
        M(1, x: 2);
    }
}";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics(
                // (9,14): error CS1744: Named argument 'x' specifies a parameter for which a positional argument has already been given
                //         M(1, x: 2);
                Diagnostic(ErrorCode.ERR_NamedArgumentUsedInPositional, "x").WithArguments("x").WithLocation(9, 14)
                );
 
            var tree = comp.SyntaxTrees.First();
            var model = comp.GetSemanticModel(tree);
            var nodes = tree.GetCompilationUnitRoot().DescendantNodes();
            var invocation = nodes.OfType<InvocationExpressionSyntax>().Single();
            Assert.Equal("M(1, x: 2)", invocation.ToString());
            Assert.Null(model.GetSymbolInfo(invocation).Symbol);
        }
 
        [Fact]
        public void TestNamedParamsVariousForms()
        {
            var source = @"
class C
{
    static void M(int x, params string[] y)
    {
        System.Console.Write($""{x} {string.Join("","", y)}. "");
    }
    static void Main()
    {
        M(x: 1, y: ""2"");
        M(x: 2, ""3"");
        M(x: 3, new[] { ""4"", ""5"" });
    }
}";
            var comp = CompileAndVerify(source, expectedOutput: "1 2. 2 3. 3 4,5.");
            comp.VerifyDiagnostics();
        }
 
        [Fact]
        public void TestTwiceNamedParams()
        {
            var source = @"
class C
{
    static void M(params int[] x)
    {
    }
    static void Main()
    {
        M(x: 1, x: 2);
    }
}";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics(
                // (9,17): error CS1740: Named argument 'x' cannot be specified multiple times
                //         M(x: 1, x: 2);
                Diagnostic(ErrorCode.ERR_DuplicateNamedArgument, "x").WithArguments("x").WithLocation(9, 17)
                );
 
            var tree = comp.SyntaxTrees.First();
            var model = comp.GetSemanticModel(tree);
            var nodes = tree.GetCompilationUnitRoot().DescendantNodes();
            var invocation = nodes.OfType<InvocationExpressionSyntax>().Single();
            Assert.Equal("M(x: 1, x: 2)", invocation.ToString());
 
            var symbolInfo = model.GetSymbolInfo(invocation);
            Assert.Null(symbolInfo.Symbol);
            Assert.Equal(CandidateReason.OverloadResolutionFailure, symbolInfo.CandidateReason);
            Assert.Equal("void C.M(params System.Int32[] x)", symbolInfo.CandidateSymbols.Single().ToTestDisplayString());
        }
 
        [Fact]
        public void TestTwiceNamedParamsWithOldLangVer()
        {
            var source = @"
class C
{
    static void M(int x, int y, int z)
    {
    }
    static void Main()
    {
        M(x: 1, x: 2, 3);
    }
}";
            var comp = CreateCompilation(source, parseOptions: TestOptions.Regular7_1);
            comp.VerifyDiagnostics(
                // (9,23): error CS1738: Named argument specifications must appear after all fixed arguments have been specified. Please use language version 7.2 or greater to allow non-trailing named arguments.
                //         M(x: 1, x: 2, 3);
                Diagnostic(ErrorCode.ERR_NamedArgumentSpecificationBeforeFixedArgument, "3").WithArguments("7.2").WithLocation(9, 23),
                // (9,17): error CS8323: Named argument 'x' is used out-of-position but is followed by an unnamed argument
                //         M(x: 1, x: 2, 3);
                Diagnostic(ErrorCode.ERR_BadNonTrailingNamedArgument, "x").WithArguments("x").WithLocation(9, 17));
 
            var tree = comp.SyntaxTrees.First();
            var model = comp.GetSemanticModel(tree);
            var nodes = tree.GetCompilationUnitRoot().DescendantNodes();
            var invocation = nodes.OfType<InvocationExpressionSyntax>().Single();
            Assert.Equal("M(x: 1, x: 2, 3)", invocation.ToString());
            Assert.Null(model.GetSymbolInfo(invocation).Symbol);
        }
 
        [Fact]
        public void TestNamedParams3()
        {
            var source = @"
class C
{
    static void M(int x, params int[] y)
    {
    }
    static void Main()
    {
        M(y: 1, 2);
    }
}";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics(
                // (9,11): error CS8321: Named argument 'y' is used out-of-position but is followed by an unnamed argument
                //         M(y: 1, 2);
                Diagnostic(ErrorCode.ERR_BadNonTrailingNamedArgument, "y").WithArguments("y").WithLocation(9, 11)
                );
 
            var tree = comp.SyntaxTrees.First();
            var model = comp.GetSemanticModel(tree);
            var nodes = tree.GetCompilationUnitRoot().DescendantNodes();
            var invocation = nodes.OfType<InvocationExpressionSyntax>().Single();
            Assert.Equal("M(y: 1, 2)", invocation.ToString());
            Assert.Null(model.GetSymbolInfo(invocation).Symbol);
        }
 
        [Fact]
        public void TestNamedParams4()
        {
            var source = @"
class C
{
    static void M(int x, params int[] y)
    {
    }
    static void Main()
    {
        M(x: 1, y: 2, 3);
    }
}";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics(
                // (9,9): error CS1501: No overload for method 'M' takes 3 arguments
                //         M(x: 1, y: 2, 3);
                Diagnostic(ErrorCode.ERR_BadArgCount, "M").WithArguments("M", "3").WithLocation(9, 9)
                );
        }
 
        [Fact]
        public void TestNamedInvalidParams()
        {
            var source = @"
class C
{
    static void M(params int[] x, int y)
    {
    }
    static void Main()
    {
        M(x: 1, 2);
    }
}";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics(
                // (4,19): error CS0231: A params parameter must be the last parameter in a parameter list
                //     static void M(params int[] x, int y)
                Diagnostic(ErrorCode.ERR_ParamsLast, "params int[] x").WithLocation(4, 19),
                // (9,14): error CS1503: Argument 1: cannot convert from 'int' to 'params int[]'
                //         M(x: 1, 2);
                Diagnostic(ErrorCode.ERR_BadArgType, "1").WithArguments("1", "int", "params int[]").WithLocation(9, 14)
                );
 
            var tree = comp.SyntaxTrees.First();
            var model = comp.GetSemanticModel(tree);
            var nodes = tree.GetCompilationUnitRoot().DescendantNodes();
            var invocation = nodes.OfType<InvocationExpressionSyntax>().Single();
            Assert.Equal("M(x: 1, 2)", invocation.ToString());
            Assert.Null(model.GetSymbolInfo(invocation).Symbol);
        }
 
        [Fact]
        public void TestNamedParams5()
        {
            var source = @"
class C
{
    static void M(int x, params int[] y)
    {
        System.Console.Write($""x={x} y[0]={y[0]} y.Length={y.Length}"");
    }
    static void Main()
    {
        M(y: 1, x: 2);
    }
}";
            var comp = CreateCompilation(source, options: TestOptions.DebugExe);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "x=2 y[0]=1 y.Length=1");
 
            var tree = comp.SyntaxTrees.First();
            var model = comp.GetSemanticModel(tree);
            var nodes = tree.GetCompilationUnitRoot().DescendantNodes();
            var invocation = nodes.OfType<InvocationExpressionSyntax>().ElementAt(1);
            Assert.Equal("M(y: 1, x: 2)", invocation.ToString());
            Assert.Equal("void C.M(System.Int32 x, params System.Int32[] y)", model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString());
        }
 
        [Fact]
        public void TestBadNonTrailing()
        {
            var source = @"
class C
{
    static void M(int a = 1, int b = 2, int c = 3)
    {
    }
    static void Main()
    {
        int valueB = 2;
        int valueC = 3;
        M(c: valueC, valueB);
    }
}";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics(
                // (11,11): error CS8321: Named argument 'c' is used out-of-position but is followed by an unnamed argument
                //         M(c: valueC, valueB);
                Diagnostic(ErrorCode.ERR_BadNonTrailingNamedArgument, "c").WithArguments("c").WithLocation(11, 11)
                );
 
            var tree = comp.SyntaxTrees.First();
            var model = comp.GetSemanticModel(tree);
            var nodes = tree.GetCompilationUnitRoot().DescendantNodes();
            var firstInvocation = nodes.OfType<InvocationExpressionSyntax>().Single();
            Assert.Equal("M(c: valueC, valueB)", firstInvocation.ToString());
            Assert.Null(model.GetSymbolInfo(firstInvocation).Symbol);
            Assert.Equal(CandidateReason.OverloadResolutionFailure, model.GetSymbolInfo(firstInvocation).CandidateReason);
            Assert.Equal("void C.M([System.Int32 a = 1], [System.Int32 b = 2], [System.Int32 c = 3])",
                model.GetSymbolInfo(firstInvocation).CandidateSymbols.Single().ToTestDisplayString());
        }
 
        [Fact]
        public void TestPickGoodOverload()
        {
            var source = @"
class C
{
    static void M(int a = 1, int b = 2, int c = 3)
    {
    }
    static void M(long c = 1, long b = 2)
    {
        System.Console.Write($""Second {c} {b}. "");
    }
    static void Main()
    {
        int valueB = 2;
        int valueC = 3;
        M(c: valueC, valueB);
    }
}";
            var verifier = CompileAndVerify(source, expectedOutput: "Second 3 2.");
            verifier.VerifyDiagnostics();
 
            var tree = verifier.Compilation.SyntaxTrees.First();
            var model = verifier.Compilation.GetSemanticModel(tree);
            var nodes = tree.GetCompilationUnitRoot().DescendantNodes();
            var invocation = nodes.OfType<InvocationExpressionSyntax>().ElementAt(1);
            Assert.Equal("M(c: valueC, valueB)", invocation.ToString());
            Assert.Equal("void C.M([System.Int64 c = 1], [System.Int64 b = 2])",
                model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString());
        }
 
        [Fact]
        public void TestPickGoodOverload2()
        {
            var source = @"
class C
{
    static void M(long a = 1, long b = 2, long c = 3)
    {
    }
    static void M(int c = 1, int b = 2)
    {
        System.Console.Write($""Second {c} {b}."");
    }
    static void Main()
    {
        int valueB = 2;
        int valueC = 3;
        M(c: valueC, valueB);
    }
}";
            var verifier = CompileAndVerify(source, expectedOutput: "Second 3 2.");
            verifier.VerifyDiagnostics();
 
            var tree = verifier.Compilation.SyntaxTrees.First();
            var model = verifier.Compilation.GetSemanticModel(tree);
            var nodes = tree.GetCompilationUnitRoot().DescendantNodes();
            var invocation = nodes.OfType<InvocationExpressionSyntax>().ElementAt(1);
            Assert.Equal("M(c: valueC, valueB)", invocation.ToString());
            Assert.Equal("void C.M([System.Int32 c = 1], [System.Int32 b = 2])",
                model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString());
        }
 
        [Fact]
        public void TestOptionalValues()
        {
            var source = @"
class C
{
    static void M(int a, int b, int c = 42)
    {
        System.Console.Write(c);
    }
    static void Main()
    {
        M(a: 1, 2);
    }
}";
            var comp = CompileAndVerify(source, expectedOutput: "42");
            comp.VerifyDiagnostics();
        }
 
        [Fact]
        public void TestDynamicInvocation()
        {
            var source = @"
class C
{
    void M()
    {
        dynamic d = new object();
        d.M(a: 1, 2);
        d.M(1, 2);
    }
}";
            var comp = CreateCompilation(source, parseOptions: TestOptions.Regular7_2);
            comp.VerifyDiagnostics(
                // (7,19): error CS8323: Named argument specifications must appear after all fixed arguments have been specified in a dynamic invocation.
                //         d.M(a: 1, 2);
                Diagnostic(ErrorCode.ERR_NamedArgumentSpecificationBeforeFixedArgumentInDynamicInvocation, "2").WithLocation(7, 19)
                );
 
            var comp2 = CreateCompilation(source, parseOptions: TestOptions.Regular7);
            comp2.VerifyDiagnostics(
                // (7,19): error CS1738: Named argument specifications must appear after all fixed arguments have been specified. Please use language version 7.2 or greater to allow non-trailing named arguments.
                //         d.M(a: 1, 2);
                Diagnostic(ErrorCode.ERR_NamedArgumentSpecificationBeforeFixedArgument, "2").WithArguments("7.2").WithLocation(7, 19)
                );
        }
 
        [Fact]
        public void TestInvocationWithDynamicInLocalFunctionParams()
        {
            var source = @"
class C
{
    void M()
    {
        dynamic d = new object[] { 0 };
        local(x: 1, d); 
        void local(int x, params object[] y) { }
    }
}";
            var comp = CreateCompilation(source, parseOptions: TestOptions.Regular7_2);
            comp.VerifyDiagnostics(
                // (7,21): error CS8108: Cannot pass argument with dynamic type to params parameter 'y' of local function 'local'.
                //         local(x: 1, d); 
                Diagnostic(ErrorCode.ERR_DynamicLocalFunctionParamsParameter, "d").WithArguments("y", "local").WithLocation(7, 21),
                // (7,21): error CS8323: Named argument specifications must appear after all fixed arguments have been specified in a dynamic invocation.
                //         local(x: 1, d); 
                Diagnostic(ErrorCode.ERR_NamedArgumentSpecificationBeforeFixedArgumentInDynamicInvocation, "d").WithLocation(7, 21)
                );
        }
 
        [Fact]
        public void TestDynamicWhenNotInvocation_01()
        {
            var source = @"
class C
{
    int this[int a, int b]
    {
        get
        {
            System.Console.Write($""{a} {b}."");
            return 0;
        }
    }
    void M(C c)
    {
        dynamic d = new object();
        c[a: 1, d] = d;
    }
}";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics(
                );
        }
 
        [Fact]
        public void TestDynamicWhenNotInvocation_02()
        {
            var source = @"
class C
{
    int this[int a, int b]
    {
        get
        {
            System.Console.Write($""{a} {b}."");
            return 0;
        }
    }
    int this[int a, long b]
    {
        get
        {
            return 0;
        }
    }
    void M(C c)
    {
        dynamic d = new object();
        c[a: 1, d] = d;
    }
}";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics(
                );
        }
 
        [Fact]
        public void TestParams()
        {
            var source = @"
class C
{
    static void M(int a, int b, params int[] c)
    {
    }
    static void Main()
    {
        M(b: 2, 3, 4);
    }
}";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics(
                // (9,11): error CS8321: Named argument 'b' is used out-of-position but is followed by an unnamed argument
                //         M(b: 2, 3, 4);
                Diagnostic(ErrorCode.ERR_BadNonTrailingNamedArgument, "b").WithArguments("b").WithLocation(9, 11)
                );
        }
 
        [Fact]
        public void TestParams2()
        {
            var source = @"
class C
{
    static void M(int a, int b, params int[] c)
    {
        System.Console.Write($""{a} {b} {c[0]} {c[1]} Length:{c.Length}"");
    }
    static void Main()
    {
        M(1, b: 2, 3, 4);
    }
}";
            var verifier = CompileAndVerify(source, expectedOutput: "1 2 3 4 Length:2");
            verifier.VerifyDiagnostics();
        }
 
        [Fact]
        public void TestInAttribute()
        {
            var source = @"
using System;
 
[AttributeUsage(AttributeTargets.All, AllowMultiple = true)]
public class MyAttribute : Attribute
{
    public int P { get; set; }
	public MyAttribute(bool condition, int other) { }
}
 
[MyAttribute(condition: true, 42)]
[MyAttribute(condition: true, P = 1, 42)]
[MyAttribute(42, condition: true)]
public class C
{
}";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics(
                // (12,38): error CS1016: Named attribute argument expected
                // [MyAttribute(condition: true, P = 1, 42)]
                Diagnostic(ErrorCode.ERR_NamedArgumentExpected, "42").WithLocation(12, 38),
                // (13,18): error CS1744: Named argument 'condition' specifies a parameter for which a positional argument has already been given
                // [MyAttribute(42, condition: true)]
                Diagnostic(ErrorCode.ERR_NamedArgumentUsedInPositional, "condition").WithArguments("condition").WithLocation(13, 18)
                );
 
            var tree = comp.SyntaxTrees.First();
            var model = comp.GetSemanticModel(tree);
            var nodes = tree.GetCompilationUnitRoot().DescendantNodes();
            var invocation = nodes.OfType<AttributeSyntax>().ElementAt(1);
            Assert.Equal("MyAttribute(condition: true, 42)", invocation.ToString());
            Assert.Equal("MyAttribute..ctor(System.Boolean condition, System.Int32 other)",
                model.GetSymbolInfo(invocation).Symbol.ToTestDisplayString());
        }
 
        [Fact]
        public void TestInAttributeWithOldLangVersion()
        {
            var source = @"
using System;
 
[AttributeUsage(AttributeTargets.All, AllowMultiple = true)]
public class MyAttribute : Attribute
{
    public int P { get; set; }
	public MyAttribute(bool condition, int other) { }
}
 
[MyAttribute(condition: true, 42)]
[MyAttribute(condition: true, P = 1, 42)]
[MyAttribute(42, condition: true)]
public class C
{
}";
            var comp = CreateCompilation(source, parseOptions: TestOptions.Regular7_1);
            comp.VerifyDiagnostics(
                // (11,31): error CS1738: Named argument specifications must appear after all fixed arguments have been specified. Please use language version 7.2 or greater to allow non-trailing named arguments.
                // [MyAttribute(condition: true, 42)]
                Diagnostic(ErrorCode.ERR_NamedArgumentSpecificationBeforeFixedArgument, "42").WithArguments("7.2").WithLocation(11, 31),
                // (12,38): error CS1016: Named attribute argument expected
                // [MyAttribute(condition: true, P = 1, 42)]
                Diagnostic(ErrorCode.ERR_NamedArgumentExpected, "42").WithLocation(12, 38),
                // (12,38): error CS1738: Named argument specifications must appear after all fixed arguments have been specified. Please use language version 7.2 or greater to allow non-trailing named arguments.
                // [MyAttribute(condition: true, P = 1, 42)]
                Diagnostic(ErrorCode.ERR_NamedArgumentSpecificationBeforeFixedArgument, "42").WithArguments("7.2").WithLocation(12, 38),
                // (13,18): error CS1744: Named argument 'condition' specifies a parameter for which a positional argument has already been given
                // [MyAttribute(42, condition: true)]
                Diagnostic(ErrorCode.ERR_NamedArgumentUsedInPositional, "condition").WithArguments("condition").WithLocation(13, 18)
                );
        }
 
        [Fact]
        public void TestInAttribute2()
        {
            var source = @"
using System;
 
[AttributeUsage(AttributeTargets.All, AllowMultiple = true)]
public class MyAttribute : Attribute
{
    public int P { get; set; }
	public MyAttribute(int a = 1, int b = 2, int c = 3) { }
}
 
[MyAttribute(c:3, 2)]
[MyAttribute(P=1, c:3, 2)]
public class C
{
}";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics(
                // (11,14): error CS8321: Named argument 'c' is used out-of-position but is followed by an unnamed argument
                // [MyAttribute(c:3, 2)]
                Diagnostic(ErrorCode.ERR_BadNonTrailingNamedArgument, "c").WithArguments("c").WithLocation(11, 14),
                // (12,21): error CS1016: Named attribute argument expected
                // [MyAttribute(P=1, c:3, 2)]
                Diagnostic(ErrorCode.ERR_NamedArgumentExpected, "3").WithLocation(12, 21),
                // (12,24): error CS1016: Named attribute argument expected
                // [MyAttribute(P=1, c:3, 2)]
                Diagnostic(ErrorCode.ERR_NamedArgumentExpected, "2").WithLocation(12, 24),
                // (12,19): error CS8321: Named argument 'c' is used out-of-position but is followed by an unnamed argument
                // [MyAttribute(P=1, c:3, 2)]
                Diagnostic(ErrorCode.ERR_BadNonTrailingNamedArgument, "c").WithArguments("c").WithLocation(12, 19)
                );
        }
 
        [Fact]
        public void TestErrorsDoNotCascadeInInvocation()
        {
            var source = @"
class C
{
    static void M()
    {
        M(x: 1, x: 2, __arglist());
    }
}";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics(
                // (6,11): error CS1739: The best overload for 'M' does not have a parameter named 'x'
                //         M(x: 1, x: 2, __arglist());
                Diagnostic(ErrorCode.ERR_BadNamedArgument, "x").WithArguments("M", "x").WithLocation(6, 11));
        }
 
        [Fact]
        public void TestErrorsDoNotCascadeInArglist()
        {
            var source = @"
class C
{
    static void M()
    {
        M(__arglist(x: 1, x: 2, __arglist()));
    }
}";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics(
                // (6,33): error CS0226: An __arglist expression may only appear inside of a call or new expression
                //         M(__arglist(x: 1, x: 2, __arglist()));
                Diagnostic(ErrorCode.ERR_IllegalArglist, "__arglist()").WithLocation(6, 33));
        }
 
        [ConditionalFact(typeof(DesktopOnly), Reason = ConditionalSkipReason.RestrictedTypesNeedDesktop)]
        public void TestSimpleArglist()
        {
            var source = @"
using System;
class C
{
    static void M(int x, int y, __arglist)
    {
        System.Console.Write($""{x} {y} {ArgListToString(new ArgIterator(__arglist))}. "");
    }
    static void Main()
    {
        M(1, 2, __arglist(3, 4));
        M(x: 1, 2, __arglist(5, 6));
    }
 
    static string ArgListToString(ArgIterator args)
    {
        int argCount = args.GetRemainingCount();
        string result = """";
 
        for (int i = 0; i < argCount; i++)
        {
            TypedReference tr = args.GetNextArg();
            result += TypedReference.ToObject(tr);
        }
 
        return result;
    }
}";
            var comp = CompileAndVerify(source, expectedOutput: "1 2 34. 1 2 56.");
            comp.VerifyDiagnostics();
        }
 
        [Fact]
        public void TestSimpleArglistAfterOutOfPositionArg()
        {
            var source = @"
class C
{
    static void M(int x, int y, __arglist)
    {
        M(y: 1, x: 2, __arglist(3));
    }
}";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics(
                // (6,11): error CS8322: Named argument 'y' is used out-of-position but is followed by an unnamed argument
                //         M(y: 1, x: 2, __arglist(3));
                Diagnostic(ErrorCode.ERR_BadNonTrailingNamedArgument, "y").WithArguments("y").WithLocation(6, 11)
                );
        }
 
        [Fact]
        public void TestErrorsDoNotCascadeInConstructorInitializer()
        {
            var source = @"
class C
{
    C() : this(x: 1, x: 2, 3) { }
}";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics(
                // (4,16): error CS1739: The best overload for '.ctor' does not have a parameter named 'x'
                //     C() : this(x: 1, x: 2, 3) { }
                Diagnostic(ErrorCode.ERR_BadNamedArgument, "x").WithArguments(".ctor", "x").WithLocation(4, 16));
        }
 
        [Fact]
        public void TestErrorsDoNotCascadeInObjectCreation()
        {
            var source = @"
class C
{
    void M()
    {
        new C(x: 1, x: 2, 3);
    }
}";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics(
                // (6,15): error CS1739: The best overload for 'C' does not have a parameter named 'x'
                //         new C(x: 1, x: 2, 3);
                Diagnostic(ErrorCode.ERR_BadNamedArgument, "x").WithArguments("C", "x").WithLocation(6, 15));
        }
 
        [Fact]
        public void TestErrorsDoNotCascadeInElementAccess()
        {
            var source = @"
class C
{
    int this[int i] { get { throw null; } set { throw null; } }
    void M()
    {
        var c = new C();
        System.Console.Write(c[x: 1, x: 2, 3]);
    }
}";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics(
                // (8,32): error CS1739: The best overload for 'this' does not have a parameter named 'x'
                //         System.Console.Write(c[x: 1, x: 2, 3]);
                Diagnostic(ErrorCode.ERR_BadNamedArgument, "x").WithArguments("this", "x").WithLocation(8, 32));
        }
    }
}