/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/CSharp/Test/Emit3/Semantics/CollectionExpressionTests_WithElement_Extra.cs
9 599 строк
477 KB
Copilot
Fix false positive "infinite chain of calls" error in collection expressions when parameterless constructor exists alongside params constructor (#82591)
25 апр 2026, 19:54
Не верифицирован
25 апр 2026, 19:54
415d13d
Код
Авторство
О чём код?
// 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. // #DEFINE DICTIONARY_EXPRESSIONS 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; namespace Microsoft.CodeAnalysis.CSharp.UnitTests; [CompilerTrait(CompilerFeature.CollectionExpressions)] public sealed class CollectionExpressionTests_WithElement_Extra : CSharpTestBase { private static string? IncludeExpectedOutput(string expectedOutput) => ExecutionConditionUtil.IsMonoOrCoreClr ? expectedOutput : null; private const string s_collectionExtensions = CollectionExpressionTests.s_collectionExtensions; public static readonly TheoryData<LanguageVersion> LanguageVersions = new([LanguageVersion.CSharp14, LanguageVersion.Preview, LanguageVersionFacts.CSharpNext]); [Theory] [MemberData(nameof(LanguageVersions))] public void LanguageVersion_01(LanguageVersion languageVersion) { string source = """ int[] a = [with()]; """; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); if (languageVersion == LanguageVersion.CSharp14) { comp.VerifyEmitDiagnostics( // (1,12): error CS8652: The feature 'collection expression arguments' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // int[] a = [with()]; Diagnostic(ErrorCode.ERR_FeatureInPreview, "with").WithArguments("collection expression arguments").WithLocation(1, 12), // (1,12): error CS9401: 'with(...)' elements are not supported for type 'int[]' // int[] a = [with()]; Diagnostic(ErrorCode.ERR_CollectionArgumentsNotSupportedForType, "with").WithArguments("int[]").WithLocation(1, 12)); } else { comp.VerifyEmitDiagnostics( // (1,12): error CS9336: Collection arguments are not supported for type 'int[]'. // int[] a = [with()]; Diagnostic(ErrorCode.ERR_CollectionArgumentsNotSupportedForType, "with").WithArguments("int[]").WithLocation(1, 12)); } } [Theory] [MemberData(nameof(LanguageVersions))] public void LanguageVersion_02(LanguageVersion languageVersion) { string source = """ using System.Collections.Generic; List<int> l = [1, with(), 3, with(capacity: 4)]; """; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); if (languageVersion == LanguageVersion.CSharp14) { comp.VerifyEmitDiagnostics( // (2,19): error CS8652: The feature 'collection expression arguments' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // List<int> l = [1, with(), 3, with(capacity: 4)]; Diagnostic(ErrorCode.ERR_FeatureInPreview, "with").WithArguments("collection expression arguments").WithLocation(2, 19), // (2,19): error CS9400: 'with(...)' element must be the first element // List<int> l = [1, with(), 3, with(capacity: 4)]; Diagnostic(ErrorCode.ERR_CollectionArgumentsMustBeFirst, "with").WithLocation(2, 19), // (2,30): error CS8652: The feature 'collection expression arguments' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // List<int> l = [1, with(), 3, with(capacity: 4)]; Diagnostic(ErrorCode.ERR_FeatureInPreview, "with").WithArguments("collection expression arguments").WithLocation(2, 30), // (2,30): error CS9400: 'with(...)' element must be the first element // List<int> l = [1, with(), 3, with(capacity: 4)]; Diagnostic(ErrorCode.ERR_CollectionArgumentsMustBeFirst, "with").WithLocation(2, 30)); } else { comp.VerifyEmitDiagnostics( // (2,19): error CS9501: Collection argument element must be the first element. // List<int> l = [1, with(), 3, with(capacity: 4)]; Diagnostic(ErrorCode.ERR_CollectionArgumentsMustBeFirst, "with").WithLocation(2, 19), // (2,30): error CS9501: Collection argument element must be the first element. // List<int> l = [1, with(), 3, with(capacity: 4)]; Diagnostic(ErrorCode.ERR_CollectionArgumentsMustBeFirst, "with").WithLocation(2, 30)); } } [Theory] [MemberData(nameof(LanguageVersions))] public void LanguageVersion_03(LanguageVersion languageVersion) { string source = """ using System.Collections.Generic; List<int> l = [with(x: 1), with(y: 2)]; """; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); if (languageVersion == LanguageVersion.CSharp14) { comp.VerifyEmitDiagnostics( // (2,16): error CS8652: The feature 'collection expression arguments' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // List<int> l = [with(x: 1), with(y: 2)]; Diagnostic(ErrorCode.ERR_FeatureInPreview, "with").WithArguments("collection expression arguments").WithLocation(2, 16), // (2,28): error CS8652: The feature 'collection expression arguments' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // List<int> l = [with(x: 1), with(y: 2)]; Diagnostic(ErrorCode.ERR_FeatureInPreview, "with").WithArguments("collection expression arguments").WithLocation(2, 28), // (2,28): error CS9400: 'with(...)' element must be the first element // List<int> l = [with(x: 1), with(y: 2)]; Diagnostic(ErrorCode.ERR_CollectionArgumentsMustBeFirst, "with").WithLocation(2, 28)); } else { comp.VerifyEmitDiagnostics( // (2,28): error CS9335: Collection argument element must be the first element. // List<int> l = [with(x: 1), with(y: 2)]; Diagnostic(ErrorCode.ERR_CollectionArgumentsMustBeFirst, "with").WithLocation(2, 28)); } } [Theory] [MemberData(nameof(LanguageVersions))] public void LanguageVersion_04(LanguageVersion languageVersion) { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] struct MyCollection<T> : IEnumerable<T> { IEnumerator<T> IEnumerable<T>.GetEnumerator() => default; IEnumerator IEnumerable.GetEnumerator() => default; } class MyBuilder { public static MyCollection<T> Create<T>(ReadOnlySpan<T> items, T arg = default) => default; } """; string sourceB = """ MyCollection<int> c = [ with(), with(arg: 0), with(unknown: 1)]; """; var comp = CreateCompilation( [sourceA, sourceB], parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), targetFramework: TargetFramework.Net80); if (languageVersion == LanguageVersion.CSharp14) { comp.VerifyEmitDiagnostics( // (2,5): error CS8652: The feature 'collection expression arguments' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // with(), Diagnostic(ErrorCode.ERR_FeatureInPreview, "with").WithArguments("collection expression arguments").WithLocation(2, 5), // (3,5): error CS8652: The feature 'collection expression arguments' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // with(arg: 0), Diagnostic(ErrorCode.ERR_FeatureInPreview, "with").WithArguments("collection expression arguments").WithLocation(3, 5), // (3,5): error CS9400: 'with(...)' element must be the first element // with(arg: 0), Diagnostic(ErrorCode.ERR_CollectionArgumentsMustBeFirst, "with").WithLocation(3, 5), // (4,5): error CS8652: The feature 'collection expression arguments' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // with(unknown: 1)]; Diagnostic(ErrorCode.ERR_FeatureInPreview, "with").WithArguments("collection expression arguments").WithLocation(4, 5), // (4,5): error CS9400: 'with(...)' element must be the first element // with(unknown: 1)]; Diagnostic(ErrorCode.ERR_CollectionArgumentsMustBeFirst, "with").WithLocation(4, 5)); } else { comp.VerifyEmitDiagnostics( // (3,5): error CS9501: Collection argument element must be the first element. // with(arg: 0), Diagnostic(ErrorCode.ERR_CollectionArgumentsMustBeFirst, "with").WithLocation(3, 5), // (4,5): error CS9501: Collection argument element must be the first element. // with(unknown: 1)]; Diagnostic(ErrorCode.ERR_CollectionArgumentsMustBeFirst, "with").WithLocation(4, 5)); } } [Theory] [MemberData(nameof(LanguageVersions))] public void LanguageVersion_05(LanguageVersion languageVersion) { string source = """ using System.Collections.Generic; List<string> list; list = [with(capacity: 1), "one"]; list.Report(); list = [@with(capacity: 2), "two"]; list.Report(); string with(int capacity) => $"with({capacity})"; """; if (languageVersion == LanguageVersion.CSharp14) { CreateCompilation([source, s_collectionExtensions], parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)).VerifyDiagnostics( // (3,9): error CS8652: The feature 'collection expression arguments' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // list = [with(capacity: 1), "one"]; Diagnostic(ErrorCode.ERR_FeatureInPreview, "with").WithArguments("collection expression arguments").WithLocation(3, 9)); } else { var verifier = CompileAndVerify([source, s_collectionExtensions], parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), expectedOutput: "[one], [with(2), two], "); verifier.VerifyDiagnostics(); } } [Fact] public void EmptyArguments_Array1() { string source = """ class Program { static void Main() { NoArgs<int>().Report(); } static T[] NoArgs<T>() => []; } """; var verifier = CompileAndVerify( [source, s_collectionExtensions], expectedOutput: "[], "); verifier.VerifyDiagnostics(); string expectedIL = """ { // Code size 6 (0x6) .maxstack 1 IL_0000: call "T[] System.Array.Empty<T>()" IL_0005: ret } """; verifier.VerifyIL("Program.NoArgs<T>", expectedIL); } [Fact] public void EmptyArguments_Array2() { string source = """ class Program { static void Main() { EmptyArgs<int>().Report(); } static T[] EmptyArgs<T>() => [with()]; } """; var verifier = CreateCompilation( [source, s_collectionExtensions]); verifier.VerifyDiagnostics( // (7,35): error CS9336: Collection arguments are not supported for type 'T[]'. // static T[] EmptyArgs<T>() => [with()]; Diagnostic(ErrorCode.ERR_CollectionArgumentsNotSupportedForType, "with").WithArguments("T[]").WithLocation(7, 35)); } [Fact] public void Arguments_Array() { string source = """ class Program { static void F<T>(T t) { T[] a; a = [with(default), t]; a = [t, with(default)]; } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (6,14): error CS9401: 'with(...)' elements are not supported for type 'T[]' // a = [with(default), t]; Diagnostic(ErrorCode.ERR_CollectionArgumentsNotSupportedForType, "with").WithArguments("T[]").WithLocation(6, 14), // (6,19): error CS8716: There is no target type for the default literal. // a = [with(default), t]; Diagnostic(ErrorCode.ERR_DefaultLiteralNoTargetType, "default").WithLocation(6, 19), // (7,17): error CS9400: 'with(...)' element must be the first element // a = [t, with(default)]; Diagnostic(ErrorCode.ERR_CollectionArgumentsMustBeFirst, "with").WithLocation(7, 17)); // Collection arguments do not affect convertibility. var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var collections = tree.GetRoot().DescendantNodes().OfType<CollectionExpressionSyntax>().ToArray(); Assert.Equal(2, collections.Length); VerifyTypes(model, collections[0], expectedType: null, expectedConvertedType: "T[]", ConversionKind.CollectionExpression); VerifyTypes(model, collections[1], expectedType: null, expectedConvertedType: "T[]", ConversionKind.NoConversion); } private static void VerifyTypes(SemanticModel model, ExpressionSyntax expr, string? expectedType, string expectedConvertedType, ConversionKind expectedConversionKind) { var typeInfo = model.GetTypeInfo(expr); var conversion = model.GetConversion(expr); Assert.Equal(expectedType, typeInfo.Type?.ToTestDisplayString()); Assert.Equal(expectedConvertedType, typeInfo.ConvertedType?.ToTestDisplayString()); Assert.Equal(expectedConversionKind, conversion.Kind); } [Theory] [InlineData("ReadOnlySpan")] [InlineData("Span")] public void EmptyArguments_Span(string spanType) { string source = $$""" using System; class Program { static void Main() { NoArgs<int>().Report(); EmptyArgs<int>().Report(); } static T[] NoArgs<T>() { {{spanType}}<T> x = []; return x.ToArray(); } static T[] EmptyArgs<T>() { {{spanType}}<T> x = [with()]; return x.ToArray(); } } """; var verifier = CreateCompilation( [source, s_collectionExtensions], targetFramework: TargetFramework.Net80); verifier.VerifyDiagnostics( // (16,30): error CS9336: Collection arguments are not supported for type 'ReadOnlySpan<T>'. // ReadOnlySpan<T> x = [with()]; Diagnostic(ErrorCode.ERR_CollectionArgumentsNotSupportedForType, "with").WithArguments($"System.{spanType}<T>")); } [Theory] [InlineData("System.ReadOnlySpan<T>")] [InlineData("System.Span<T>")] public void Arguments_Span(string spanType) { string source = $$""" class Program { static void F<T>(T t) { {{spanType}} x = [with(default), t]; {{spanType}} y = [t, with(default)]; } } """; var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (7,14): error CS9401: 'with(...)' elements are not supported for type 'Span<T>' // [with(default), t]; Diagnostic(ErrorCode.ERR_CollectionArgumentsNotSupportedForType, "with").WithArguments(spanType), // (7,19): error CS8716: There is no target type for the default literal. // [with(default), t]; Diagnostic(ErrorCode.ERR_DefaultLiteralNoTargetType, "default").WithLocation(6, 19), // (9,17): error CS9400: 'with(...)' element must be the first element // [t, with(default)]; Diagnostic(ErrorCode.ERR_CollectionArgumentsMustBeFirst, "with").WithLocation(8, 17)); } [Fact] public void EmptyArguments_List_01() { string source = """ using System.Collections.Generic; class Program { static void Main() { NoArgs<int>().Report(); EmptyArgs<int>().Report(); } static List<T> NoArgs<T>() => []; static List<T> EmptyArgs<T>() => [with()]; } """; var verifier = CompileAndVerify( [source, s_collectionExtensions], targetFramework: TargetFramework.Net80, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("[], [], ")); verifier.VerifyDiagnostics(); string expectedIL = """ { // Code size 6 (0x6) .maxstack 1 IL_0000: newobj "System.Collections.Generic.List<T>..ctor()" IL_0005: ret } """; verifier.VerifyIL("Program.NoArgs<T>", expectedIL); verifier.VerifyIL("Program.EmptyArgs<T>", expectedIL); } [Fact] public void EmptyArguments_List_02() { string source = """ using System.Collections.Generic; class Program { static void Main() { NoArgs<int>(1, 2).Report(); EmptyArgs<int>(3, 4).Report(); } static List<T> NoArgs<T>(T x, T y) => [x, y]; static List<T> EmptyArgs<T>(T x, T y) => [with(), x, y]; } """; var verifier = CompileAndVerify( [source, s_collectionExtensions], targetFramework: TargetFramework.Net80, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("[1, 2], [3, 4], ")); verifier.VerifyDiagnostics(); verifier.VerifyIL("Program.NoArgs<T>", """ { // Code size 51 (0x33) .maxstack 3 .locals init (int V_0, System.Span<T> V_1) IL_0000: ldc.i4.2 IL_0001: stloc.0 IL_0002: ldloc.0 IL_0003: newobj "System.Collections.Generic.List<T>..ctor(int)" IL_0008: dup IL_0009: ldloc.0 IL_000a: call "void System.Runtime.InteropServices.CollectionsMarshal.SetCount<T>(System.Collections.Generic.List<T>, int)" IL_000f: dup IL_0010: call "System.Span<T> System.Runtime.InteropServices.CollectionsMarshal.AsSpan<T>(System.Collections.Generic.List<T>)" IL_0015: stloc.1 IL_0016: ldloca.s V_1 IL_0018: ldc.i4.0 IL_0019: call "ref T System.Span<T>.this[int].get" IL_001e: ldarg.0 IL_001f: stobj "T" IL_0024: ldloca.s V_1 IL_0026: ldc.i4.1 IL_0027: call "ref T System.Span<T>.this[int].get" IL_002c: ldarg.1 IL_002d: stobj "T" IL_0032: ret } """); verifier.VerifyIL("Program.EmptyArgs<T>", """ { // Code size 20 (0x14) .maxstack 3 IL_0000: newobj "System.Collections.Generic.List<T>..ctor()" IL_0005: dup IL_0006: ldarg.0 IL_0007: callvirt "void System.Collections.Generic.List<T>.Add(T)" IL_000c: dup IL_000d: ldarg.1 IL_000e: callvirt "void System.Collections.Generic.List<T>.Add(T)" IL_0013: ret } """); } [Fact] public void Arguments_List() { string source = """ using System; using System.Collections.Generic; class Program { static void Main() { var l = F(1); l.Report(); Console.WriteLine(l.Capacity); } static List<T> F<T>(T t) => [with(capacity: 2), t]; } """; var verifier = CompileAndVerify( [source, s_collectionExtensions], expectedOutput: "[1], 2"); verifier.VerifyDiagnostics(); verifier.VerifyIL("Program.F<T>(T)", """ { // Code size 14 (0xe) .maxstack 3 IL_0000: ldc.i4.2 IL_0001: newobj "System.Collections.Generic.List<T>..ctor(int)" IL_0006: dup IL_0007: ldarg.0 IL_0008: callvirt "void System.Collections.Generic.List<T>.Add(T)" IL_000d: ret } """); } [Theory] [CombinatorialData] public void List_KnownLength_ICollection( [CombinatorialValues("", "with(), ", "with(3), ")] string argsPrefix) { string source = $$""" using System.Collections.Generic; class Program { static void Main() { Create(1, 2, 3).Report(); } static ICollection<T> Create<T>(params T[] items) { return [{{argsPrefix}} ..items]; } } """; var verifier = CompileAndVerify( [source, s_collectionExtensions], targetFramework: TargetFramework.Net80, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("[1, 2, 3], ")); verifier.VerifyDiagnostics(); string expectedIL; switch (argsPrefix) { case "with(), ": expectedIL = """ { // Code size 15 (0xf) .maxstack 3 .locals init (T[] V_0) IL_0000: ldarg.0 IL_0001: stloc.0 IL_0002: newobj "System.Collections.Generic.List<T>..ctor()" IL_0007: dup IL_0008: ldloc.0 IL_0009: callvirt "void System.Collections.Generic.List<T>.AddRange(System.Collections.Generic.IEnumerable<T>)" IL_000e: ret } """; break; case "with(3), ": expectedIL = """ { // Code size 16 (0x10) .maxstack 3 .locals init (T[] V_0) IL_0000: ldarg.0 IL_0001: stloc.0 IL_0002: ldc.i4.3 IL_0003: newobj "System.Collections.Generic.List<T>..ctor(int)" IL_0008: dup IL_0009: ldloc.0 IL_000a: callvirt "void System.Collections.Generic.List<T>.AddRange(System.Collections.Generic.IEnumerable<T>)" IL_000f: ret } """; break; default: expectedIL = """ { // Code size 69 (0x45) .maxstack 5 .locals init (T[] V_0, int V_1, System.Span<T> V_2, int V_3, System.ReadOnlySpan<T> V_4) IL_0000: ldarg.0 IL_0001: stloc.0 IL_0002: ldloc.0 IL_0003: ldlen IL_0004: conv.i4 IL_0005: stloc.1 IL_0006: ldloc.1 IL_0007: newobj "System.Collections.Generic.List<T>..ctor(int)" IL_000c: dup IL_000d: ldloc.1 IL_000e: call "void System.Runtime.InteropServices.CollectionsMarshal.SetCount<T>(System.Collections.Generic.List<T>, int)" IL_0013: dup IL_0014: call "System.Span<T> System.Runtime.InteropServices.CollectionsMarshal.AsSpan<T>(System.Collections.Generic.List<T>)" IL_0019: stloc.2 IL_001a: ldc.i4.0 IL_001b: stloc.3 IL_001c: ldloca.s V_4 IL_001e: ldloc.0 IL_001f: call "System.ReadOnlySpan<T>..ctor(T[])" IL_0024: ldloca.s V_4 IL_0026: ldloca.s V_2 IL_0028: ldloc.3 IL_0029: ldloca.s V_4 IL_002b: call "int System.ReadOnlySpan<T>.Length.get" IL_0030: call "System.Span<T> System.Span<T>.Slice(int, int)" IL_0035: call "void System.ReadOnlySpan<T>.CopyTo(System.Span<T>)" IL_003a: ldloc.3 IL_003b: ldloca.s V_4 IL_003d: call "int System.ReadOnlySpan<T>.Length.get" IL_0042: add IL_0043: stloc.3 IL_0044: ret } """; break; } verifier.VerifyIL("Program.Create<T>", expectedIL); } /// <summary> /// Implementation of List(int) uses a name other than capacity. /// </summary> [Fact] public void InterfaceTarget_ImplementationParameterName() { string sourceA = """ namespace System { public class Object { } public abstract class ValueType { } public class String { } public class Type { } public struct Void { } public struct Boolean { } public struct Int32 { } public class Array { } public interface IDisposable { void Dispose(); } } namespace System.Collections { public interface IEnumerator { bool MoveNext(); object Current { get; } } public interface IEnumerable { IEnumerator GetEnumerator(); } } namespace System.Collections.Generic { public interface IEnumerator<T> : IEnumerator { new T Current { get; } } public interface IEnumerable<T> : IEnumerable { new IEnumerator<T> GetEnumerator(); } public interface ICollection<T> : IEnumerable<T> { } public class List<T> : ICollection<T> { public List() { } public List(int __c) { } public void Add(T t) { } public T[] ToArray() => null; IEnumerator<T> IEnumerable<T>.GetEnumerator() => null; IEnumerator IEnumerable.GetEnumerator() => null; } } """; string sourceB = """ using System.Collections.Generic; class Program { static void Main() { Create(1, 2); } static ICollection<T> Create<T>(T x, T y) { return [with(capacity: 3), x, y]; } } """; var comp = CreateEmptyCompilation( [sourceA, sourceB], parseOptions: TestOptions.RegularPreview.WithNoRefSafetyRulesAttribute(), options: TestOptions.ReleaseExe).VerifyDiagnostics( // (10,22): error CS1739: The best overload for 'List' does not have a parameter named 'capacity' // return [with(capacity: 3), x, y]; Diagnostic(ErrorCode.ERR_BadNamedArgument, "capacity").WithArguments("List", "capacity").WithLocation(10, 22)); } [Theory] [InlineData("IEnumerable")] [InlineData("IReadOnlyCollection")] [InlineData("IReadOnlyList")] [InlineData("ICollection")] [InlineData("IList")] public void EmptyArguments_ArrayInterface(string interfaceType) { string source = $$""" using System.Collections.Generic; class Program { static void Main() { NoArgs<int>().Report(); EmptyArgs<int>().Report(); } static {{interfaceType}}<T> NoArgs<T>() => []; static {{interfaceType}}<T> EmptyArgs<T>() => [with()]; } """; var verifier = CompileAndVerify( [source, s_collectionExtensions], verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("[], [], ")); verifier.VerifyDiagnostics(); string expectedIL; if (interfaceType is "IEnumerable" or "IReadOnlyCollection" or "IReadOnlyList") { expectedIL = """ { // Code size 6 (0x6) .maxstack 1 IL_0000: call "T[] System.Array.Empty<T>()" IL_0005: ret } """; } else { expectedIL = """ { // Code size 6 (0x6) .maxstack 1 IL_0000: newobj "System.Collections.Generic.List<T>..ctor()" IL_0005: ret } """; } verifier.VerifyIL("Program.NoArgs<T>", expectedIL); verifier.VerifyIL("Program.EmptyArgs<T>", expectedIL); } [Theory] [CombinatorialData] public void InterfaceTarget_ArrayInterfaces( [CombinatorialValues("IEnumerable", "IReadOnlyCollection", "IReadOnlyList", "ICollection", "IList")] string typeName) { bool isMutable = typeName is "ICollection" or "IList"; string sourceA = $$""" using System.Collections.Generic; class Program { static void Main() { Create(1, 2, 3).Report(); } static {{typeName}}<T> Create<T>(T x, T y, T z) { return [with(), x, y, z]; } } """; var comp = CreateCompilation( [sourceA, s_collectionExtensions], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify( comp, expectedOutput: "[1, 2, 3], "); verifier.VerifyDiagnostics(); verifier.VerifyIL("Program.Create<T>", isMutable ? """ { // Code size 27 (0x1b) .maxstack 3 IL_0000: newobj "System.Collections.Generic.List<T>..ctor()" IL_0005: dup IL_0006: ldarg.0 IL_0007: callvirt "void System.Collections.Generic.List<T>.Add(T)" IL_000c: dup IL_000d: ldarg.1 IL_000e: callvirt "void System.Collections.Generic.List<T>.Add(T)" IL_0013: dup IL_0014: ldarg.2 IL_0015: callvirt "void System.Collections.Generic.List<T>.Add(T)" IL_001a: ret } """ : """ { // Code size 36 (0x24) .maxstack 4 IL_0000: ldc.i4.3 IL_0001: newarr "T" IL_0006: dup IL_0007: ldc.i4.0 IL_0008: ldarg.0 IL_0009: stelem "T" IL_000e: dup IL_000f: ldc.i4.1 IL_0010: ldarg.1 IL_0011: stelem "T" IL_0016: dup IL_0017: ldc.i4.2 IL_0018: ldarg.2 IL_0019: stelem "T" IL_001e: newobj "<>z__ReadOnlyArray<T>..ctor(T[])" IL_0023: ret } """); string sourceB = $$""" using System.Collections.Generic; class Program { static void Main() { Create1(2, 1, 2, 3).Report(); Create2(2, 4, 5, 6).Report(); } static {{typeName}}<T> Create1<T>(int c, T x, T y, T z) { return [with(c), x, y, z]; } static {{typeName}}<T> Create2<T>(int c, T x, T y, T z) { return [with(capacity: c), x, y, z]; } } """; comp = CreateCompilation( [sourceB, s_collectionExtensions], options: TestOptions.ReleaseExe); if (isMutable) { verifier = CompileAndVerify( comp, expectedOutput: "[1, 2, 3], [4, 5, 6], "); verifier.VerifyDiagnostics(); string expectedIL = """ { // Code size 28 (0x1c) .maxstack 3 IL_0000: ldarg.0 IL_0001: newobj "System.Collections.Generic.List<T>..ctor(int)" IL_0006: dup IL_0007: ldarg.1 IL_0008: callvirt "void System.Collections.Generic.List<T>.Add(T)" IL_000d: dup IL_000e: ldarg.2 IL_000f: callvirt "void System.Collections.Generic.List<T>.Add(T)" IL_0014: dup IL_0015: ldarg.3 IL_0016: callvirt "void System.Collections.Generic.List<T>.Add(T)" IL_001b: ret } """; verifier.VerifyIL("Program.Create1<T>", expectedIL); verifier.VerifyIL("Program.Create2<T>", expectedIL); } else { comp.VerifyEmitDiagnostics( // (11,17): error CS9338: 'with(...)' element for a read-only interface must be empty if present // return [with(c), x, y, z]; Diagnostic(ErrorCode.ERR_CollectionArgumentsMustBeEmpty, "with").WithLocation(11, 17), // (15,17): error CS9338: 'with(...)' element for a read-only interface must be empty if present // return [with(capacity: c), x, y, z]; Diagnostic(ErrorCode.ERR_CollectionArgumentsMustBeEmpty, "with").WithLocation(15, 17)); } string sourceC = $$""" using System.Collections.Generic; class Program { static {{typeName}}<T> Create1<T>(IEnumerable<T> c, T x, T y, T z) { return [with(c), x, y, z]; } static {{typeName}}<T> Create2<T>(IEnumerable<T> c, T x, T y, T z) { return [with(collection: c), x, y, z]; } } """; comp = CreateCompilation(sourceC); if (isMutable) { comp.VerifyEmitDiagnostics( // (6,22): error CS1503: Argument 1: cannot convert from 'System.Collections.Generic.IEnumerable<T>' to 'int' // return [with(c), x, y, z]; Diagnostic(ErrorCode.ERR_BadArgType, "c").WithArguments("1", "System.Collections.Generic.IEnumerable<T>", "int").WithLocation(6, 22), // (10,22): error CS1739: The best overload for 'List' does not have a parameter named 'collection' // return [with(collection: c), x, y, z]; Diagnostic(ErrorCode.ERR_BadNamedArgument, "collection").WithArguments("List", "collection").WithLocation(10, 22)); } else { comp.VerifyEmitDiagnostics( // (6,17): error CS9338: 'with(...)' element for a read-only interface must be empty if present // return [with(c), x, y, z]; Diagnostic(ErrorCode.ERR_CollectionArgumentsMustBeEmpty, "with").WithLocation(6, 17), // (10,17): error CS9338: 'with(...)' element for a read-only interface must be empty if present // return [with(collection: c), x, y, z]; Diagnostic(ErrorCode.ERR_CollectionArgumentsMustBeEmpty, "with").WithLocation(10, 17)); } } [Theory] [CombinatorialData] public void CollectionArguments_CapacityAndComparer_01( [CombinatorialValues( "T[]", "System.ReadOnlySpan<T>", "System.Span<T>", "System.Collections.Generic.IEnumerable<T>", "System.Collections.Generic.IReadOnlyCollection<T>", "System.Collections.Generic.IReadOnlyList<T>", "System.Collections.Generic.ICollection<T>", "System.Collections.Generic.IList<T>")] string typeName) { string source = $$""" using System.Collections.Generic; class Program { static void Create<T>(int capacity, IEqualityComparer<T> comparer) { {{typeName}} c; c = []; c = [with()]; c = [with(default)]; c = [with(capacity)]; c = [with(comparer)]; c = [with(capacity, comparer)]; } } """; var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); switch (typeName) { case "T[]": case "System.ReadOnlySpan<T>": case "System.Span<T>": comp.VerifyEmitDiagnostics( // (8,14): error CS9401: 'with(...)' elements are not supported for type 'ReadOnlySpan<T>' // c = [with()]; Diagnostic(ErrorCode.ERR_CollectionArgumentsNotSupportedForType, "with").WithArguments(typeName).WithLocation(8, 14), // (9,14): error CS9401: 'with(...)' elements are not supported for type 'ReadOnlySpan<T>' // c = [with(default)]; Diagnostic(ErrorCode.ERR_CollectionArgumentsNotSupportedForType, "with").WithArguments(typeName).WithLocation(9, 14), // (9,19): error CS8716: There is no target type for the default literal. // c = [with(default)]; Diagnostic(ErrorCode.ERR_DefaultLiteralNoTargetType, "default").WithLocation(9, 19), // (10,14): error CS9401: 'with(...)' elements are not supported for type 'ReadOnlySpan<T>' // c = [with(capacity)]; Diagnostic(ErrorCode.ERR_CollectionArgumentsNotSupportedForType, "with").WithArguments(typeName).WithLocation(10, 14), // (11,14): error CS9401: 'with(...)' elements are not supported for type 'ReadOnlySpan<T>' // c = [with(comparer)]; Diagnostic(ErrorCode.ERR_CollectionArgumentsNotSupportedForType, "with").WithArguments(typeName).WithLocation(11, 14), // (12,14): error CS9401: 'with(...)' elements are not supported for type 'ReadOnlySpan<T>' // c = [with(capacity, comparer)]; Diagnostic(ErrorCode.ERR_CollectionArgumentsNotSupportedForType, "with").WithArguments(typeName).WithLocation(12, 14)); break; case "System.Collections.Generic.IEnumerable<T>": case "System.Collections.Generic.IReadOnlyCollection<T>": case "System.Collections.Generic.IReadOnlyList<T>": comp.VerifyEmitDiagnostics( // (9,14): error CS9403: 'with(...)' element for a read-only interface must be empty if present // c = [with(default)]; Diagnostic(ErrorCode.ERR_CollectionArgumentsMustBeEmpty, "with").WithLocation(9, 14), // (9,19): error CS8716: There is no target type for the default literal. // c = [with(default)]; Diagnostic(ErrorCode.ERR_DefaultLiteralNoTargetType, "default").WithLocation(9, 19), // (10,14): error CS9403: 'with(...)' element for a read-only interface must be empty if present // c = [with(capacity)]; Diagnostic(ErrorCode.ERR_CollectionArgumentsMustBeEmpty, "with").WithLocation(10, 14), // (11,14): error CS9403: 'with(...)' element for a read-only interface must be empty if present // c = [with(comparer)]; Diagnostic(ErrorCode.ERR_CollectionArgumentsMustBeEmpty, "with").WithLocation(11, 14), // (12,14): error CS9403: 'with(...)' element for a read-only interface must be empty if present // c = [with(capacity, comparer)]; Diagnostic(ErrorCode.ERR_CollectionArgumentsMustBeEmpty, "with").WithLocation(12, 14)); break; case "System.Collections.Generic.ICollection<T>": case "System.Collections.Generic.IList<T>": comp.VerifyEmitDiagnostics( // (11,19): error CS1503: Argument 1: cannot convert from 'System.Collections.Generic.IEqualityComparer<T>' to 'int' // c = [with(comparer)]; Diagnostic(ErrorCode.ERR_BadArgType, "comparer").WithArguments("1", "System.Collections.Generic.IEqualityComparer<T>", "int").WithLocation(11, 19), // (12,14): error CS1729: 'List<T>' does not contain a constructor that takes 2 arguments // c = [with(capacity, comparer)]; Diagnostic(ErrorCode.ERR_BadCtorArgCount, "with").WithArguments("System.Collections.Generic.List<T>", "2").WithLocation(12, 14)); break; default: throw ExceptionUtilities.UnexpectedValue(typeName); } } [Theory] [InlineData("IEnumerable")] [InlineData("IReadOnlyCollection")] [InlineData("IReadOnlyList")] [InlineData("ICollection")] [InlineData("IList")] public void Arguments_ArrayInterface(string interfaceType) { string source = $$""" using System.Collections.Generic; class Program { static void F<T>(T t) { {{interfaceType}}<T> i; i = [with(default), t]; i = [t, with(default)]; } } """; var comp = CreateCompilation(source); if (interfaceType is "ICollection" or "IList") { comp.VerifyEmitDiagnostics( // (8,17): error CS9501: Collection argument element must be the first element. // i = [t, with(default)]; Diagnostic(ErrorCode.ERR_CollectionArgumentsMustBeFirst, "with").WithLocation(8, 17)); } else { comp.VerifyEmitDiagnostics( // (7,14): error CS9403: 'with(...)' element for a read-only interface must be empty if present // i = [with(default), t]; Diagnostic(ErrorCode.ERR_CollectionArgumentsMustBeEmpty, "with").WithLocation(7, 14), // (7,19): error CS8716: There is no target type for the default literal. // i = [with(default), t]; Diagnostic(ErrorCode.ERR_DefaultLiteralNoTargetType, "default").WithLocation(7, 19), // (8,17): error CS9400: 'with(...)' element must be the first element // i = [t, with(default)]; Diagnostic(ErrorCode.ERR_CollectionArgumentsMustBeFirst, "with").WithLocation(8, 17)); } // Collection arguments do not affect convertibility. var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var collections = tree.GetRoot().DescendantNodes().OfType<CollectionExpressionSyntax>().ToArray(); Assert.Equal(2, collections.Length); VerifyTypes(model, collections[0], expectedType: null, expectedConvertedType: $"System.Collections.Generic.{interfaceType}<T>", ConversionKind.CollectionExpression); VerifyTypes(model, collections[1], expectedType: null, expectedConvertedType: $"System.Collections.Generic.{interfaceType}<T>", ConversionKind.NoConversion); } [Fact] public void CollectionInitializer_MultipleConstructors() { string sourceA = """ using System.Collections; using System.Collections.Generic; class MyCollection<T> : IEnumerable<T> { public readonly T Arg; public MyCollection() { } public MyCollection(T arg) { Arg = arg; } public void Add(T t) { } IEnumerator<T> IEnumerable<T>.GetEnumerator() => throw null; IEnumerator IEnumerable.GetEnumerator() => throw null; } """; string sourceB = """ using System; class Program { static void Main() { Console.WriteLine((EmptyArgs<int>().Arg, NonEmptyArgs(2).Arg)); } static MyCollection<T> EmptyArgs<T>() => [with()]; static MyCollection<T> NonEmptyArgs<T>(T t) => [with(t)]; } """; var verifier = CompileAndVerify( [sourceA, sourceB], expectedOutput: "(0, 2)"); verifier.VerifyDiagnostics(); verifier.VerifyIL("Program.EmptyArgs<T>()", """ { // Code size 6 (0x6) .maxstack 1 IL_0000: newobj "MyCollection<T>..ctor()" IL_0005: ret } """); verifier.VerifyIL("Program.NonEmptyArgs<T>(T)", """ { // Code size 7 (0x7) .maxstack 1 IL_0000: ldarg.0 IL_0001: newobj "MyCollection<T>..ctor(T)" IL_0006: ret } """); } [Fact] public void CollectionInitializer_NoParameterlessConstructor() { string source = """ using System.Collections; using System.Collections.Generic; class MyCollection<T> : IEnumerable<T> { public readonly T Arg; public MyCollection(T arg) { Arg = arg; } public void Add(T t) { } IEnumerator<T> IEnumerable<T>.GetEnumerator() => null; IEnumerator IEnumerable.GetEnumerator() => null; } class Program { static MyCollection<T> EmptyArgs<T>() => [with()]; static MyCollection<T> NonEmptyArgs<T>(T t) => [with(t)]; } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (13,47): error CS7036: There is no argument given that corresponds to the required parameter 'arg' of 'MyCollection<T>.MyCollection(T)' // static MyCollection<T> EmptyArgs<T>() => [with()]; Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "with()").WithArguments("arg", "MyCollection<T>.MyCollection(T)").WithLocation(13, 47)); } [Fact] public void CollectionInitializer_OptionalParameter() { string sourceA = """ using System.Collections; using System.Collections.Generic; class MyCollection<T> : IEnumerable<T> { public readonly T Arg; public MyCollection(T arg = default) { Arg = arg; } public void Add(T t) { } IEnumerator<T> IEnumerable<T>.GetEnumerator() => throw null; IEnumerator IEnumerable.GetEnumerator() => throw null; } """; string sourceB = """ using System; class Program { static void Main() { Console.WriteLine((EmptyArgs<int>().Arg, NonEmptyArgs(2).Arg)); } static MyCollection<T> EmptyArgs<T>() => [with()]; static MyCollection<T> NonEmptyArgs<T>(T t) => [with(t)]; } """; var verifier = CompileAndVerify( [sourceA, sourceB], expectedOutput: "(0, 2)"); verifier.VerifyDiagnostics(); verifier.VerifyIL("Program.EmptyArgs<T>()", """ { // Code size 15 (0xf) .maxstack 1 .locals init (T V_0) IL_0000: ldloca.s V_0 IL_0002: initobj "T" IL_0008: ldloc.0 IL_0009: newobj "MyCollection<T>..ctor(T)" IL_000e: ret } """); verifier.VerifyIL("Program.NonEmptyArgs<T>(T)", """ { // Code size 7 (0x7) .maxstack 1 IL_0000: ldarg.0 IL_0001: newobj "MyCollection<T>..ctor(T)" IL_0006: ret } """); } [Fact] public void CollectionInitializer_ParamsParameter() { string sourceA = """ using System.Collections; using System.Collections.Generic; class MyCollection<T> : IEnumerable<T> { public readonly T[] Args; public MyCollection(params T[] args) { Args = args; } public void Add(T t) { } IEnumerator<T> IEnumerable<T>.GetEnumerator() => throw null; IEnumerator IEnumerable.GetEnumerator() => throw null; } """; string sourceB = """ class Program { static void Main() { EmptyArgs<int>().Args.Report(); OneArg(1).Args.Report(); TwoArgs(2, 3).Args.Report(); MultipleArgs([4, 5]).Args.Report(); } static MyCollection<T> EmptyArgs<T>() => [with()]; static MyCollection<T> OneArg<T>(T t) => [with(t)]; static MyCollection<T> TwoArgs<T>(T x, T y) => [with(x, y)]; static MyCollection<T> MultipleArgs<T>(T[] args) => [with(args)]; } """; var verifier = CompileAndVerify( [sourceA, sourceB, s_collectionExtensions], expectedOutput: "[], [1], [2, 3], [4, 5], "); verifier.VerifyDiagnostics(); verifier.VerifyIL("Program.EmptyArgs<T>()", """ { // Code size 11 (0xb) .maxstack 1 IL_0000: call "T[] System.Array.Empty<T>()" IL_0005: newobj "MyCollection<T>..ctor(params T[])" IL_000a: ret } """); verifier.VerifyIL("Program.OneArg<T>(T)", """ { // Code size 20 (0x14) .maxstack 4 IL_0000: ldc.i4.1 IL_0001: newarr "T" IL_0006: dup IL_0007: ldc.i4.0 IL_0008: ldarg.0 IL_0009: stelem "T" IL_000e: newobj "MyCollection<T>..ctor(params T[])" IL_0013: ret } """); verifier.VerifyIL("Program.TwoArgs<T>(T, T)", """ { // Code size 28 (0x1c) .maxstack 4 IL_0000: ldc.i4.2 IL_0001: newarr "T" IL_0006: dup IL_0007: ldc.i4.0 IL_0008: ldarg.0 IL_0009: stelem "T" IL_000e: dup IL_000f: ldc.i4.1 IL_0010: ldarg.1 IL_0011: stelem "T" IL_0016: newobj "MyCollection<T>..ctor(params T[])" IL_001b: ret } """); verifier.VerifyIL("Program.MultipleArgs<T>(T[])", """ { // Code size 7 (0x7) .maxstack 1 IL_0000: ldarg.0 IL_0001: newobj "MyCollection<T>..ctor(params T[])" IL_0006: ret } """); } [Fact] public void CollectionInitializer_ObsoleteConstructor_01() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; class MyCollection<T> : IEnumerable<T> { public MyCollection() { } [Obsolete] public MyCollection(T arg) { } public void Add(T t) { } IEnumerator<T> IEnumerable<T>.GetEnumerator() => throw null; IEnumerator IEnumerable.GetEnumerator() => throw null; } """; string sourceB = """ class Program { static void Main() { MyCollection<int> c; c = [with()]; c = [with(default)]; } static void F<T>(params MyCollection<T> c) { } } """; var comp = CreateCompilation([sourceA, sourceB]); comp.VerifyEmitDiagnostics( // (7,14): warning CS0612: 'MyCollection<int>.MyCollection(int)' is obsolete // c = [with(default)]; Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "with(default)").WithArguments("MyCollection<int>.MyCollection(int)").WithLocation(7, 14)); } [Fact] public void CollectionInitializer_ObsoleteConstructor_02() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; class MyCollection<T> : IEnumerable<T> { [Obsolete] public MyCollection(T arg = default) { } public void Add(T t) { } IEnumerator<T> IEnumerable<T>.GetEnumerator() => throw null; IEnumerator IEnumerable.GetEnumerator() => throw null; } """; string sourceB = """ class Program { static void Main() { MyCollection<int> c; c = [with()]; c = [with(default)]; } static void F<T>(params MyCollection<T> c) { } } """; var comp = CreateCompilation([sourceA, sourceB]); comp.VerifyEmitDiagnostics( // (6,14): warning CS0612: 'MyCollection<int>.MyCollection(int)' is obsolete // c = [with()]; Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "with()").WithArguments("MyCollection<int>.MyCollection(int)").WithLocation(6, 14), // (7,14): warning CS0612: 'MyCollection<int>.MyCollection(int)' is obsolete // c = [with(default)]; Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "with(default)").WithArguments("MyCollection<int>.MyCollection(int)").WithLocation(7, 14), // (9,22): warning CS0612: 'MyCollection<T>.MyCollection(T)' is obsolete // static void F<T>(params MyCollection<T> c) { } Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "params MyCollection<T> c").WithArguments("MyCollection<T>.MyCollection(T)").WithLocation(9, 22)); } [Fact] public void TypeInference_CollectionBuilder() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyCollection<T> : IEnumerable<T> { private readonly List<T> _items; public MyCollection(T[] args, ReadOnlySpan<T> items) { _items = new(); _items.AddRange(items.ToArray()); _items.AddRange(args); } public IEnumerator<T> GetEnumerator() => _items.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } class MyBuilder { public static MyCollection<T> Create<T>(ReadOnlySpan<T> items, params T[] args) => new(args, items); } """; string sourceB = """ class Program { static void Main() { Identity([with()]); Identity([with(default, 2), default]); Identity([with(default), default, 3]); } static MyCollection<T> Identity<T>(MyCollection<T> c) => c; } """; var comp = CreateCompilation( [sourceA, sourceB], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (5,9): error CS0411: The type arguments for method 'Program.Identity<T>(MyCollection<T>)' cannot be inferred from the usage. Try specifying the type arguments explicitly. // Identity([with()]); Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "Identity").WithArguments("Program.Identity<T>(MyCollection<T>)").WithLocation(5, 9), // (6,9): error CS0411: The type arguments for method 'Program.Identity<T>(MyCollection<T>)' cannot be inferred from the usage. Try specifying the type arguments explicitly. // Identity([with(default, 2), default]); Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "Identity").WithArguments("Program.Identity<T>(MyCollection<T>)").WithLocation(6, 9), // (7,18): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // Identity([with(default), default, 3]); Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[with(default), default, 3]").WithArguments("Create", "T", "MyCollection<T>").WithLocation(7, 18), // (7,24): error CS8716: There is no target type for the default literal. // Identity([with(default), default, 3]); Diagnostic(ErrorCode.ERR_DefaultLiteralNoTargetType, "default").WithLocation(7, 24), // (7,34): error CS8716: There is no target type for the default literal. // Identity([with(default), default, 3]); Diagnostic(ErrorCode.ERR_DefaultLiteralNoTargetType, "default").WithLocation(7, 34)); } [Fact] public void TypeInference_CollectionBuilder_Nullable() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyCollection<T> : IEnumerable<T> { public MyCollection(ReadOnlySpan<T> items) { } public IEnumerator<T> GetEnumerator() => null; IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } class MyBuilder { public static MyCollection<T> Create<T>(int length, ReadOnlySpan<T> items) => new(items); } """; string sourceB = """ #nullable enable using System; class Program { static void Main() { string? s = null; Identity<int>([with((s = "").Length)]); Console.WriteLine(s.Length); } static MyCollection<T> Identity<T>(MyCollection<T> c) => c; } """; var comp = CreateCompilation( [sourceA, sourceB], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics(); } [Fact] public void CollectionBuilder_MultipleBuilderMethods() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyCollection<T> : IEnumerable<T> { public readonly T Arg; private readonly List<T> _items; public MyCollection(T arg, ReadOnlySpan<T> items) { Arg = arg; _items = new(items.ToArray()); } public IEnumerator<T> GetEnumerator() => _items.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } class MyBuilder { public static MyCollection<T> Create<T>(ReadOnlySpan<T> items) => new(default, items); public static MyCollection<T> Create<T>(ReadOnlySpan<T> items, T arg) => new(arg, items); } """; string sourceB = """ using System; class Program { static void Main() { MyCollection<int> c; c = EmptyArgs(1); Console.Write("{0}, ", c.Arg); c.Report(); c = NonEmptyArgs<int>(2); Console.Write("{0}, ", c.Arg); c.Report(); } static MyCollection<T> EmptyArgs<T>(T t) => [with(), t]; static MyCollection<T> NonEmptyArgs<T>(T t) => [with(t), t]; } """; var comp = CreateCompilation( [sourceA, sourceB, s_collectionExtensions], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (15,53): error CS9405: No overload for method 'Create' takes 1 'with(...)' element arguments // static MyCollection<T> NonEmptyArgs<T>(T t) => [with(t), t]; Diagnostic(ErrorCode.ERR_BadCollectionArgumentsArgCount, "with(t)").WithArguments("Create", "1").WithLocation(15, 53)); } [Fact] public void CollectionBuilder_MultipleBuilderMethods_A() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyCollection<T> : IEnumerable<T> { public readonly T Arg; private readonly List<T> _items; public MyCollection(T arg, ReadOnlySpan<T> items) { Arg = arg; _items = new(items.ToArray()); } public IEnumerator<T> GetEnumerator() => _items.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } class MyBuilder { public static MyCollection<T> Create<T>(ReadOnlySpan<T> items) => new(default, items); public static MyCollection<T> Create<T>(T arg, ReadOnlySpan<T> items) => new(arg, items); } """; string sourceB = """ using System; class Program { static void Main() { MyCollection<int> c; c = EmptyArgs(1); Console.Write("{0}, ", c.Arg); c.Report(); c = NonEmptyArgs<int>(2); Console.Write("{0}, ", c.Arg); c.Report(); } static MyCollection<T> EmptyArgs<T>(T t) => [with(), t]; static MyCollection<T> NonEmptyArgs<T>(T t) => [with(t), t]; } """; var verifier = CompileAndVerify( [sourceA, sourceB, s_collectionExtensions], targetFramework: TargetFramework.Net80, expectedOutput: IncludeExpectedOutput("0, [1], 2, [2], "), verify: Verification.FailsPEVerify); verifier.VerifyDiagnostics(); var compilation = (CSharpCompilation)verifier.Compilation; var semanticModel = compilation.GetSemanticModel(compilation.SyntaxTrees.ToArray()[1]); var root = semanticModel.SyntaxTree.GetRoot(); var withElements = root.DescendantNodes().OfType<WithElementSyntax>().ToArray(); Assert.Equal(2, withElements.Length); var method1 = (IMethodSymbol?)semanticModel.GetSymbolInfo(withElements[0]).Symbol; var method2 = (IMethodSymbol?)semanticModel.GetSymbolInfo(withElements[1]).Symbol; Assert.NotNull(method1); Assert.NotNull(method2); Assert.NotEqual(method1, method2); Assert.Equal("MyBuilder", method1.ContainingType.Name); AssertEx.Equal("MyCollection<T> MyBuilder.Create<T>(System.ReadOnlySpan<T> items)", method1.ToTestDisplayString()); AssertEx.Equal("MyCollection<T> MyBuilder.Create<T>(T arg, System.ReadOnlySpan<T> items)", method2.ToTestDisplayString()); var arrowExpressions = root.DescendantNodes().OfType<ArrowExpressionClauseSyntax>().ToArray(); var operation1 = semanticModel.GetOperation(arrowExpressions[0]); VerifyOperationTree(compilation, operation1, """ IBlockOperation (1 statements) (OperationKind.Block, Type: null) (Syntax: '=> [with(), t]') IReturnOperation (OperationKind.Return, Type: null, IsImplicit) (Syntax: '[with(), t]') ReturnedValue: IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: MyCollection<T>, IsImplicit) (Syntax: '[with(), t]') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Operand: ICollectionExpressionOperation (1 elements, ConstructMethod: MyCollection<T> MyBuilder.Create<T>(System.ReadOnlySpan<T> items)) (OperationKind.CollectionExpression, Type: MyCollection<T>) (Syntax: '[with(), t]') ConstructArguments(1): IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: items) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'with()') ICollectionExpressionElementsPlaceholderOperation (OperationKind.CollectionExpressionElementsPlaceholder, Type: System.ReadOnlySpan<T>, IsImplicit) (Syntax: 'with()') InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Elements(1): IParameterReferenceOperation: t (OperationKind.ParameterReference, Type: T) (Syntax: 't') """); var operation2 = semanticModel.GetOperation(arrowExpressions[1]); VerifyOperationTree(compilation, operation2, """ IBlockOperation (1 statements) (OperationKind.Block, Type: null) (Syntax: '=> [with(t), t]') IReturnOperation (OperationKind.Return, Type: null, IsImplicit) (Syntax: '[with(t), t]') ReturnedValue: IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: MyCollection<T>, IsImplicit) (Syntax: '[with(t), t]') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Operand: ICollectionExpressionOperation (1 elements, ConstructMethod: MyCollection<T> MyBuilder.Create<T>(T arg, System.ReadOnlySpan<T> items)) (OperationKind.CollectionExpression, Type: MyCollection<T>) (Syntax: '[with(t), t]') ConstructArguments(2): IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: arg) (OperationKind.Argument, Type: null) (Syntax: 't') IParameterReferenceOperation: t (OperationKind.ParameterReference, Type: T) (Syntax: 't') InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: items) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'with(t)') ICollectionExpressionElementsPlaceholderOperation (OperationKind.CollectionExpressionElementsPlaceholder, Type: System.ReadOnlySpan<T>, IsImplicit) (Syntax: 'with(t)') InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Elements(1): IParameterReferenceOperation: t (OperationKind.ParameterReference, Type: T) (Syntax: 't') """); } [Fact] public void IList_With_SemanticModel() { var source = """ using System.Collections.Generic; class Program { static void Main() { IList<int> x = [with(), 1, 2, 3]; IList<int> y = [with(capacity: 6), 1, 2, 3]; } } """; var verifier = CompileAndVerify(source); verifier.VerifyDiagnostics(); var compilation = (CSharpCompilation)verifier.Compilation; var semanticModel = compilation.GetSemanticModel(compilation.SyntaxTrees.Single()); SyntaxNode root = semanticModel.SyntaxTree.GetRoot(); var withElements = root.DescendantNodes().OfType<WithElementSyntax>().ToArray(); Assert.Equal(2, withElements.Length); var method1 = (IMethodSymbol?)semanticModel.GetSymbolInfo(withElements[0]).Symbol; var method2 = (IMethodSymbol?)semanticModel.GetSymbolInfo(withElements[1]).Symbol; AssertEx.Equal("System.Collections.Generic.List<System.Int32>..ctor()", method1.ToTestDisplayString()); AssertEx.Equal("System.Collections.Generic.List<System.Int32>..ctor(System.Int32 capacity)", method2.ToTestDisplayString()); var operation = semanticModel.GetOperation(root.DescendantNodes().OfType<BlockSyntax>().Single()); VerifyOperationTree(compilation, operation, """ IBlockOperation (2 statements, 2 locals) (OperationKind.Block, Type: null) (Syntax: '{ ... }') Locals: Local_1: System.Collections.Generic.IList<System.Int32> x Local_2: System.Collections.Generic.IList<System.Int32> y IVariableDeclarationGroupOperation (1 declarations) (OperationKind.VariableDeclarationGroup, Type: null) (Syntax: 'IList<int> ... , 1, 2, 3];') IVariableDeclarationOperation (1 declarators) (OperationKind.VariableDeclaration, Type: null) (Syntax: 'IList<int> ... ), 1, 2, 3]') Declarators: IVariableDeclaratorOperation (Symbol: System.Collections.Generic.IList<System.Int32> x) (OperationKind.VariableDeclarator, Type: null) (Syntax: 'x = [with(), 1, 2, 3]') Initializer: IVariableInitializerOperation (OperationKind.VariableInitializer, Type: null) (Syntax: '= [with(), 1, 2, 3]') IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Collections.Generic.IList<System.Int32>, IsImplicit) (Syntax: '[with(), 1, 2, 3]') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Operand: ICollectionExpressionOperation (3 elements, ConstructMethod: System.Collections.Generic.List<System.Int32>..ctor()) (OperationKind.CollectionExpression, Type: System.Collections.Generic.IList<System.Int32>) (Syntax: '[with(), 1, 2, 3]') Elements(3): ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1') ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 2) (Syntax: '2') ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 3) (Syntax: '3') Initializer: null IVariableDeclarationGroupOperation (1 declarations) (OperationKind.VariableDeclarationGroup, Type: null) (Syntax: 'IList<int> ... , 1, 2, 3];') IVariableDeclarationOperation (1 declarators) (OperationKind.VariableDeclaration, Type: null) (Syntax: 'IList<int> ... ), 1, 2, 3]') Declarators: IVariableDeclaratorOperation (Symbol: System.Collections.Generic.IList<System.Int32> y) (OperationKind.VariableDeclarator, Type: null) (Syntax: 'y = [with(c ... ), 1, 2, 3]') Initializer: IVariableInitializerOperation (OperationKind.VariableInitializer, Type: null) (Syntax: '= [with(cap ... ), 1, 2, 3]') IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Collections.Generic.IList<System.Int32>, IsImplicit) (Syntax: '[with(capac ... ), 1, 2, 3]') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Operand: ICollectionExpressionOperation (3 elements, ConstructMethod: System.Collections.Generic.List<System.Int32>..ctor(System.Int32 capacity)) (OperationKind.CollectionExpression, Type: System.Collections.Generic.IList<System.Int32>) (Syntax: '[with(capac ... ), 1, 2, 3]') ConstructArguments(1): IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: capacity) (OperationKind.Argument, Type: null) (Syntax: 'capacity: 6') ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 6) (Syntax: '6') InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Elements(3): ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1') ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 2) (Syntax: '2') ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 3) (Syntax: '3') Initializer: null """); var (graph, symbol) = ControlFlowGraphVerifier.GetControlFlowGraph(root.DescendantNodes().OfType<BlockSyntax>().Single(), semanticModel); ControlFlowGraphVerifier.VerifyGraph(compilation, """ Block[B0] - Entry Statements (0) Next (Regular) Block[B1] Entering: {R1} .locals {R1} { Locals: [System.Collections.Generic.IList<System.Int32> x] [System.Collections.Generic.IList<System.Int32> y] Block[B1] - Block Predecessors: [B0] Statements (2) ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Collections.Generic.IList<System.Int32>, IsImplicit) (Syntax: 'x = [with(), 1, 2, 3]') Left: ILocalReferenceOperation: x (IsDeclaration: True) (OperationKind.LocalReference, Type: System.Collections.Generic.IList<System.Int32>, IsImplicit) (Syntax: 'x = [with(), 1, 2, 3]') Right: IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Collections.Generic.IList<System.Int32>, IsImplicit) (Syntax: '[with(), 1, 2, 3]') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) (CollectionExpression) Operand: ICollectionExpressionOperation (3 elements, ConstructMethod: System.Collections.Generic.List<System.Int32>..ctor()) (OperationKind.CollectionExpression, Type: System.Collections.Generic.IList<System.Int32>) (Syntax: '[with(), 1, 2, 3]') Elements(3): ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1') ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 2) (Syntax: '2') ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 3) (Syntax: '3') ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Collections.Generic.IList<System.Int32>, IsImplicit) (Syntax: 'y = [with(c ... ), 1, 2, 3]') Left: ILocalReferenceOperation: y (IsDeclaration: True) (OperationKind.LocalReference, Type: System.Collections.Generic.IList<System.Int32>, IsImplicit) (Syntax: 'y = [with(c ... ), 1, 2, 3]') Right: IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Collections.Generic.IList<System.Int32>, IsImplicit) (Syntax: '[with(capac ... ), 1, 2, 3]') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) (CollectionExpression) Operand: ICollectionExpressionOperation (3 elements, ConstructMethod: System.Collections.Generic.List<System.Int32>..ctor(System.Int32 capacity)) (OperationKind.CollectionExpression, Type: System.Collections.Generic.IList<System.Int32>) (Syntax: '[with(capac ... ), 1, 2, 3]') ConstructArguments(1): IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: capacity) (OperationKind.Argument, Type: null) (Syntax: 'capacity: 6') ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 6) (Syntax: '6') InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Elements(3): ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1') ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 2) (Syntax: '2') ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 3) (Syntax: '3') Next (Regular) Block[B2] Leaving: {R1} } Block[B2] - Exit Predecessors: [B1] Statements (0) """, graph, symbol); } private static string CreateCustomListDefinition(string constructors) { return $$""" namespace System.Collections.Generic { public class List<T> : IList<T> { {{constructors}} public T this[int index] { get => throw null; set => throw null; } public int Count => throw null; public bool IsReadOnly => throw null; public void Add(T item) { } public void Clear() => throw null; public bool Contains(T item) => throw null; public void CopyTo(T[] array, int arrayIndex) => throw null; public IEnumerator<T> GetEnumerator() => throw null; public int IndexOf(T item) => throw null; public void Insert(int index, T item) => throw null; public bool Remove(T item) => throw null; public void RemoveAt(int index) => throw null; IEnumerator IEnumerable.GetEnumerator() => throw null; public T[] ToArray() => throw null; } } """; } [Theory] [InlineData("IList<System.Int32>")] [InlineData("ICollection<System.Int32>")] public void IList_With_DifferentCapacityName(string typeName) { var source = $$""" using System.Collections.Generic; class Program { static void Main() { {{typeName}} x = [with(), 1, 2, 3]; {{typeName}} y = [with(cap: 6), 1, 2, 3]; } } """; var compilation = CreateCompilation([ source, CreateCustomListDefinition("""public List() { System.Console.Write("empty "); } public List(int cap) { System.Console.Write(cap); }""")], options: TestOptions.ReleaseExe); CompileAndVerify(compilation, expectedOutput: "empty 6").VerifyDiagnostics(); } [Theory] [InlineData("IList<System.Int32>")] [InlineData("ICollection<System.Int32>")] public void IList_With_DifferentCapacityName2(string typeName) { var source = $$""" using System.Collections.Generic; class Program { static void Main() { {{typeName}} x = [with(), 1, 2, 3]; {{typeName}} y = [with(capacity: 6), 1, 2, 3]; } } """; CreateCompilation([ source, CreateCustomListDefinition("""public List() { } public List(int cap) { }""")]).VerifyDiagnostics( // (8,45): error CS1739: The best overload for 'List' does not have a parameter named 'capacity' // ICollection<System.Int32> y = [with(capacity: 6), 1, 2, 3]; Diagnostic(ErrorCode.ERR_BadNamedArgument, "capacity").WithArguments("List", "capacity")); } [Theory] [InlineData("IList<System.Int32>")] [InlineData("ICollection<System.Int32>")] public void IList_With_DifferentCapacityType(string typeName) { var source = $$""" using System.Collections.Generic; class Program { static void Main() { {{typeName}} x = [with(), 1, 2, 3]; {{typeName}} y = [with(capacity: 6), 1, 2, 3]; {{typeName}} z = [with(6), 1, 2, 3]; } } """; CreateCompilation([ source, CreateCustomListDefinition("""public List() { } public List(long capacity) { }""")]).VerifyDiagnostics( // (7,39): error CS0656: Missing compiler required member 'System.Collections.Generic.List`1..ctor' // ICollection<System.Int32> x = [with(), 1, 2, 3]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[with(), 1, 2, 3]").WithArguments("System.Collections.Generic.List`1", ".ctor"), // (8,39): error CS0656: Missing compiler required member 'System.Collections.Generic.List`1..ctor' // ICollection<System.Int32> y = [with(capacity: 6), 1, 2, 3]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[with(capacity: 6), 1, 2, 3]").WithArguments("System.Collections.Generic.List`1", ".ctor"), // (8,45): error CS1739: The best overload for 'List' does not have a parameter named 'capacity' // ICollection<System.Int32> y = [with(capacity: 6), 1, 2, 3]; Diagnostic(ErrorCode.ERR_BadNamedArgument, "capacity").WithArguments("List", "capacity"), // (9,39): error CS0656: Missing compiler required member 'System.Collections.Generic.List`1..ctor' // ICollection<System.Int32> y = [with(6), 1, 2, 3]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[with(6), 1, 2, 3]").WithArguments("System.Collections.Generic.List`1", ".ctor"), // (9,40): error CS1729: 'List<int>' does not contain a constructor that takes 1 arguments // ICollection<System.Int32> y = [with(6), 1, 2, 3]; Diagnostic(ErrorCode.ERR_BadCtorArgCount, "with").WithArguments("System.Collections.Generic.List<int>", "1")); } [Theory] [InlineData("IList<System.Int32>")] [InlineData("ICollection<System.Int32>")] public void IList_With_ParamsCapacity(string typeName) { var source = $$""" using System.Collections.Generic; class Program { static void Main() { {{typeName}} x = [with(), 1, 2, 3]; {{typeName}} y = [with(6), 1, 2, 3]; } } """; CreateCompilation([ source, CreateCustomListDefinition("""public List() { } public List(params int[] capacity) { }""")]).VerifyDiagnostics( // (7,39): error CS0656: Missing compiler required member 'System.Collections.Generic.List`1..ctor' // ICollection<System.Int32> x = [with(), 1, 2, 3]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[with(), 1, 2, 3]").WithArguments("System.Collections.Generic.List`1", ".ctor"), // (8,39): error CS0656: Missing compiler required member 'System.Collections.Generic.List`1..ctor' // ICollection<System.Int32> y = [with(6), 1, 2, 3]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[with(6), 1, 2, 3]").WithArguments("System.Collections.Generic.List`1", ".ctor"), // (8,40): error CS1729: 'List<int>' does not contain a constructor that takes 1 arguments // ICollection<System.Int32> y = [with(6), 1, 2, 3]; Diagnostic(ErrorCode.ERR_BadCtorArgCount, "with").WithArguments("System.Collections.Generic.List<int>", "1")); } [Theory] [InlineData("IList<System.Int32>")] [InlineData("ICollection<System.Int32>")] public void IList_With_OptionalIntCapacity(string typeName) { var source = $$""" using System.Collections.Generic; class Program { static void Main() { {{typeName}} x = [with(), 1, 2, 3]; {{typeName}} y = [with(6), 1, 2, 3]; {{typeName}} z = [with(capacity: 5), 1, 2, 3]; } } """; var compilation = CreateCompilation([ source, CreateCustomListDefinition("""public List() { System.Console.Write("empty "); } public List(int capacity = 0) { System.Console.Write(capacity + " "); }""")], options: TestOptions.ReleaseExe); CompileAndVerify(compilation, expectedOutput: "empty 6 5").VerifyDiagnostics(); } [Theory] [InlineData("IList<System.Int32>")] [InlineData("ICollection<System.Int32>")] public void IList_With_OptionalNonIntCapacity(string typeName) { var source = $$""" using System.Collections.Generic; class Program { static void Main() { {{typeName}} x = [with(), 1, 2, 3]; {{typeName}} y = [with(6), 1, 2, 3]; {{typeName}} z = [with(capacity: 6), 1, 2, 3]; } } """; CreateCompilation([ source, CreateCustomListDefinition("""public List() { } public List(long capacity = 0) { }""")]).VerifyDiagnostics( // (7,39): error CS0656: Missing compiler required member 'System.Collections.Generic.List`1..ctor' // ICollection<System.Int32> x = [with(), 1, 2, 3]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[with(), 1, 2, 3]").WithArguments("System.Collections.Generic.List`1", ".ctor"), // (8,39): error CS0656: Missing compiler required member 'System.Collections.Generic.List`1..ctor' // ICollection<System.Int32> y = [with(6), 1, 2, 3]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[with(6), 1, 2, 3]").WithArguments("System.Collections.Generic.List`1", ".ctor"), // (8,40): error CS1729: 'List<int>' does not contain a constructor that takes 1 arguments // ICollection<System.Int32> y = [with(6), 1, 2, 3]; Diagnostic(ErrorCode.ERR_BadCtorArgCount, "with").WithArguments("System.Collections.Generic.List<int>", "1"), // (9,39): error CS0656: Missing compiler required member 'System.Collections.Generic.List`1..ctor' // ICollection<System.Int32> z = [with(capacity: 6), 1, 2, 3]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[with(capacity: 6), 1, 2, 3]").WithArguments("System.Collections.Generic.List`1", ".ctor"), // (9,45): error CS1739: The best overload for 'List' does not have a parameter named 'capacity' // ICollection<System.Int32> z = [with(capacity: 6), 1, 2, 3]; Diagnostic(ErrorCode.ERR_BadNamedArgument, "capacity").WithArguments("List", "capacity")); } [Theory] [InlineData("IList<System.Int32>")] [InlineData("ICollection<System.Int32>")] public void IList_With_OptionalParamsAfterCapacity(string typeName) { var source = $$""" using System.Collections.Generic; class Program { static void Main() { {{typeName}} a = [with(), 1, 2, 3]; {{typeName}} b = [with(6), 1, 2, 3]; {{typeName}} c = [with(capacity: 6), 1, 2, 3]; {{typeName}} d = [with(6, 0), 1, 2, 3]; {{typeName}} e = [with(capacity: 6, other: 0), 1, 2, 3]; {{typeName}} f = [with(other: 6, capacity: 0), 1, 2, 3]; } } """; CreateCompilation([ source, CreateCustomListDefinition("""public List() { } public List(int capacity, int other = 0) { }""")]).VerifyDiagnostics( // (7,39): error CS0656: Missing compiler required member 'System.Collections.Generic.List`1..ctor' // ICollection<System.Int32> a = [with(), 1, 2, 3]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[with(), 1, 2, 3]").WithArguments("System.Collections.Generic.List`1", ".ctor"), // (8,39): error CS0656: Missing compiler required member 'System.Collections.Generic.List`1..ctor' // ICollection<System.Int32> b = [with(6), 1, 2, 3]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[with(6), 1, 2, 3]").WithArguments("System.Collections.Generic.List`1", ".ctor"), // (8,40): error CS1729: 'List<int>' does not contain a constructor that takes 1 arguments // ICollection<System.Int32> b = [with(6), 1, 2, 3]; Diagnostic(ErrorCode.ERR_BadCtorArgCount, "with").WithArguments("System.Collections.Generic.List<int>", "1"), // (9,39): error CS0656: Missing compiler required member 'System.Collections.Generic.List`1..ctor' // ICollection<System.Int32> c = [with(capacity: 6), 1, 2, 3]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[with(capacity: 6), 1, 2, 3]").WithArguments("System.Collections.Generic.List`1", ".ctor"), // (9,45): error CS1739: The best overload for 'List' does not have a parameter named 'capacity' // ICollection<System.Int32> c = [with(capacity: 6), 1, 2, 3]; Diagnostic(ErrorCode.ERR_BadNamedArgument, "capacity").WithArguments("List", "capacity"), // (10,39): error CS0656: Missing compiler required member 'System.Collections.Generic.List`1..ctor' // ICollection<System.Int32> d = [with(6, 0), 1, 2, 3]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[with(6, 0), 1, 2, 3]").WithArguments("System.Collections.Generic.List`1", ".ctor"), // (10,40): error CS1729: 'List<int>' does not contain a constructor that takes 2 arguments // ICollection<System.Int32> d = [with(6, 0), 1, 2, 3]; Diagnostic(ErrorCode.ERR_BadCtorArgCount, "with").WithArguments("System.Collections.Generic.List<int>", "2"), // (11,39): error CS0656: Missing compiler required member 'System.Collections.Generic.List`1..ctor' // ICollection<System.Int32> e = [with(capacity: 6, other: 0), 1, 2, 3]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[with(capacity: 6, other: 0), 1, 2, 3]").WithArguments("System.Collections.Generic.List`1", ".ctor"), // (11,45): error CS1739: The best overload for 'List' does not have a parameter named 'capacity' // ICollection<System.Int32> e = [with(capacity: 6, other: 0), 1, 2, 3]; Diagnostic(ErrorCode.ERR_BadNamedArgument, "capacity").WithArguments("List", "capacity"), // (12,39): error CS0656: Missing compiler required member 'System.Collections.Generic.List`1..ctor' // ICollection<System.Int32> f = [with(other: 6, capacity: 0), 1, 2, 3]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[with(other: 6, capacity: 0), 1, 2, 3]").WithArguments("System.Collections.Generic.List`1", ".ctor"), // (12,45): error CS1739: The best overload for 'List' does not have a parameter named 'other' // ICollection<System.Int32> f = [with(other: 6, capacity: 0), 1, 2, 3]; Diagnostic(ErrorCode.ERR_BadNamedArgument, "other").WithArguments("List", "other")); } [Fact] public void CollectionBuilder_PrivateMethod1() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyCollection<T> : IEnumerable<T> { public readonly T Arg; private readonly List<T> _items; public MyCollection(T arg, ReadOnlySpan<T> items) { Arg = arg; _items = new(items.ToArray()); } public IEnumerator<T> GetEnumerator() => _items.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } class MyBuilder { public static MyCollection<T> Create<T>(ReadOnlySpan<T> items) => new(default, items); private static MyCollection<T> Create<T>(T arg, ReadOnlySpan<T> items) => new(arg, items); } """; string sourceB = """ using System; class Program { static void Main() { MyCollection<int> c; c = EmptyArgs(1); Console.Write("{0}, ", c.Arg); c.Report(); c = NonEmptyArgs<int>(2); Console.Write("{0}, ", c.Arg); c.Report(); } static MyCollection<T> EmptyArgs<T>(T t) => [with(), t]; static MyCollection<T> NonEmptyArgs<T>(T t) => [with(t), t]; } """; CreateCompilation( [sourceA, sourceB, s_collectionExtensions], targetFramework: TargetFramework.Net80).VerifyDiagnostics( // (15,53): error CS9405: No overload for method 'Create' takes 1 'with(...)' element arguments // static MyCollection<T> NonEmptyArgs<T>(T t) => [with(t), t]; Diagnostic(ErrorCode.ERR_BadCollectionArgumentsArgCount, "with(t)").WithArguments("Create", "1")); } [Fact] public void CollectionBuilder_PrivateMethod2() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyCollection<T> : IEnumerable<T> { public readonly T Arg; private readonly List<T> _items; public MyCollection(T arg, ReadOnlySpan<T> items) { Arg = arg; _items = new(items.ToArray()); } public IEnumerator<T> GetEnumerator() => _items.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } static partial class MyBuilder { private static MyCollection<T> Create<T>(ReadOnlySpan<T> items) => new(default, items); private static MyCollection<T> Create<T>(T arg, ReadOnlySpan<T> items) => new(arg, items); } """; string sourceB = """ using System; static partial class MyBuilder { static void Main() { MyCollection<int> c; c = EmptyArgs(1); Console.Write("{0}, ", c.Arg); c.Report(); c = NonEmptyArgs<int>(2); Console.Write("{0}, ", c.Arg); c.Report(); } static MyCollection<T> EmptyArgs<T>(T t) => [with(), t]; static MyCollection<T> NonEmptyArgs<T>(T t) => [with(t), t]; } """; CreateCompilation( [sourceA, sourceB, s_collectionExtensions], targetFramework: TargetFramework.Net80).VerifyDiagnostics(); } [Fact] public void CollectionBuilder_InternalMethod1() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyCollection<T> : IEnumerable<T> { public readonly T Arg; private readonly List<T> _items; public MyCollection(T arg, ReadOnlySpan<T> items) { Arg = arg; _items = new(items.ToArray()); } public IEnumerator<T> GetEnumerator() => _items.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } class MyBuilder { internal static MyCollection<T> Create<T>(ReadOnlySpan<T> items) => new(default, items); internal static MyCollection<T> Create<T>(T arg, ReadOnlySpan<T> items) => new(arg, items); } """; string sourceB = """ using System; class Program { static void Main() { MyCollection<int> c; c = EmptyArgs(1); Console.Write("{0}, ", c.Arg); c.Report(); c = NonEmptyArgs<int>(2); Console.Write("{0}, ", c.Arg); c.Report(); } static MyCollection<T> EmptyArgs<T>(T t) => [with(), t]; static MyCollection<T> NonEmptyArgs<T>(T t) => [with(t), t]; } """; CreateCompilation( [sourceA, sourceB, s_collectionExtensions], targetFramework: TargetFramework.Net80).VerifyDiagnostics(); } [Fact] public void CollectionBuilder_InternalMethod2() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] public class MyCollection<T> : IEnumerable<T> { public readonly T Arg; private readonly List<T> _items; public MyCollection(T arg, ReadOnlySpan<T> items) { Arg = arg; _items = new(items.ToArray()); } public IEnumerator<T> GetEnumerator() => _items.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } public class MyBuilder { internal static MyCollection<T> Create<T>(ReadOnlySpan<T> items) => new(default, items); internal static MyCollection<T> Create<T>(T arg, ReadOnlySpan<T> items) => new(arg, items); } """; string sourceB = """ using System; class Program { static void Main() { MyCollection<int> c; c = EmptyArgs(1); Console.Write("{0}, ", c.Arg); c.Report(); c = NonEmptyArgs<int>(2); Console.Write("{0}, ", c.Arg); c.Report(); } static MyCollection<T> EmptyArgs<T>(T t) => [with(), t]; static MyCollection<T> NonEmptyArgs<T>(T t) => [with(t), t]; } """; var compilation1 = CreateCompilation( [sourceA, s_collectionExtensions], targetFramework: TargetFramework.Net80).VerifyDiagnostics(); var compilation2 = CreateCompilation( [sourceB, s_collectionExtensions], references: [compilation1.ToMetadataReference()], targetFramework: TargetFramework.Net80).VerifyDiagnostics( // (14,49): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // static MyCollection<T> EmptyArgs<T>(T t) => [with(), t]; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[with(), t]").WithArguments("Create", "T", "MyCollection<T>").WithLocation(14, 49), // (15,52): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // static MyCollection<T> NonEmptyArgs<T>(T t) => [with(t), t]; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[with(t), t]").WithArguments("Create", "T", "MyCollection<T>").WithLocation(15, 52)); } [Fact] public void CollectionBuilder_ProtectedMethod1() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyCollection<T> : IEnumerable<T> { public readonly T Arg; private readonly List<T> _items; public MyCollection(T arg, ReadOnlySpan<T> items) { Arg = arg; _items = new(items.ToArray()); } public IEnumerator<T> GetEnumerator() => _items.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } partial class MyBuilder { protected static MyCollection<T> Create<T>(ReadOnlySpan<T> items) => new(default, items); protected static MyCollection<T> Create<T>(T arg, ReadOnlySpan<T> items) => new(arg, items); } """; string sourceB = """ using System; partial class MyBuilder { static void Main() { MyCollection<int> c; c = EmptyArgs(1); Console.Write("{0}, ", c.Arg); c.Report(); c = NonEmptyArgs<int>(2); Console.Write("{0}, ", c.Arg); c.Report(); } static MyCollection<T> EmptyArgs<T>(T t) => [with(), t]; static MyCollection<T> NonEmptyArgs<T>(T t) => [with(t), t]; } """; CreateCompilation( [sourceA, sourceB, s_collectionExtensions], targetFramework: TargetFramework.Net80).VerifyDiagnostics(); } [Fact] public void CollectionBuilder_ProtectedMethod2() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyCollection<T> : IEnumerable<T> { public readonly T Arg; private readonly List<T> _items; public MyCollection(T arg, ReadOnlySpan<T> items) { Arg = arg; _items = new(items.ToArray()); } public IEnumerator<T> GetEnumerator() => _items.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } partial class MyBuilder { protected static MyCollection<T> Create<T>(ReadOnlySpan<T> items) => new(default, items); protected static MyCollection<T> Create<T>(T arg, ReadOnlySpan<T> items) => new(arg, items); } """; string sourceB = """ using System; class Program { static void Main() { MyCollection<int> c; c = EmptyArgs(1); Console.Write("{0}, ", c.Arg); c.Report(); c = NonEmptyArgs<int>(2); Console.Write("{0}, ", c.Arg); c.Report(); } static MyCollection<T> EmptyArgs<T>(T t) => [with(), t]; static MyCollection<T> NonEmptyArgs<T>(T t) => [with(t), t]; } """; CreateCompilation( [sourceA, sourceB, s_collectionExtensions], targetFramework: TargetFramework.Net80).VerifyDiagnostics( // (14,49): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // static MyCollection<T> EmptyArgs<T>(T t) => [with(), t]; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[with(), t]").WithArguments("Create", "T", "MyCollection<T>").WithLocation(14, 49), // (15,52): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // static MyCollection<T> NonEmptyArgs<T>(T t) => [with(t), t]; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[with(t), t]").WithArguments("Create", "T", "MyCollection<T>").WithLocation(15, 52)); } [Fact] public void CollectionBuilder_NoBuilderMethodsRefSpanElementType() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyCollection : IEnumerable<ReadOnlySpan<int>> { public IEnumerator<ReadOnlySpan<int>> GetEnumerator() => null; IEnumerator IEnumerable.GetEnumerator() => null; } class MyBuilder { } """; string sourceB = """ class Program { static void Main() { MyCollection c = []; } } """; CreateCompilation( [sourceA, sourceB, s_collectionExtensions], targetFramework: TargetFramework.Net90).VerifyDiagnostics( // (5,26): error CS9404: Element type of this collection may not be a ref struct or a type parameter allowing ref structs // MyCollection c = []; Diagnostic(ErrorCode.ERR_CollectionRefLikeElementType, "[]").WithLocation(5, 26), // (5,26): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<System.ReadOnlySpan<int>>' and return type 'MyCollection'. // MyCollection c = []; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[]").WithArguments("Create", "System.ReadOnlySpan<int>", "MyCollection")); } [Fact] public void CollectionBuilder_NoParameterlessBuilderMethod() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyCollection<T> : IEnumerable<T> { IEnumerator<T> IEnumerable<T>.GetEnumerator() => null; IEnumerator IEnumerable.GetEnumerator() => null; } class MyBuilder { public static MyCollection<T> Create<T>(ReadOnlySpan<T> items, T arg) => default; } """; string sourceB = """ using System; class Program { static MyCollection<T> EmptyArgs<T>() => [with()]; static MyCollection<T> NonEmptyArgs<T>(T t) => [with(t)]; static MyCollection<T> Params<T>(params MyCollection<T> c) => c; } """; var comp = CreateCompilation([sourceA, sourceB], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (4,46): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // static MyCollection<T> EmptyArgs<T>() => [with()]; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[with()]").WithArguments("Create", "T", "MyCollection<T>").WithLocation(4, 46), // (5,52): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // static MyCollection<T> NonEmptyArgs<T>(T t) => [with(t)]; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[with(t)]").WithArguments("Create", "T", "MyCollection<T>").WithLocation(5, 52), // (6,38): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // static MyCollection<T> Params<T>(params MyCollection<T> c) => c; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "params MyCollection<T> c").WithArguments("Create", "T", "MyCollection<T>").WithLocation(6, 38)); } [Fact] public void CollectionBuilder_NoParameterlessBuilderMethod_A() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyCollection<T> : IEnumerable<T> { IEnumerator<T> IEnumerable<T>.GetEnumerator() => null; IEnumerator IEnumerable.GetEnumerator() => null; } class MyBuilder { public static MyCollection<T> Create<T>(T arg, ReadOnlySpan<T> items) => default; } """; string sourceB = """ using System; class Program { static MyCollection<T> EmptyArgs<T>() => [with()]; static MyCollection<T> NonEmptyArgs<T>(T t) => [with(t)]; static MyCollection<T> Params<T>(params MyCollection<T> c) => c; } """; var comp = CreateCompilation([sourceA, sourceB], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (4,47): error CS7036: There is no argument given that corresponds to the required parameter 'arg' of 'MyBuilder.Create<T>(T, ReadOnlySpan<T>)' // static MyCollection<T> EmptyArgs<T>() => [with()]; Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "with()").WithArguments("arg", "MyBuilder.Create<T>(T, System.ReadOnlySpan<T>)").WithLocation(4, 47), // (6,38): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // static MyCollection<T> Params<T>(params MyCollection<T> c) => c; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "params MyCollection<T> c").WithArguments("Create", "T", "MyCollection<T>").WithLocation(6, 38)); } [Fact] public void CollectionBuilder_OptionalParameter() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyCollection<T> : IEnumerable<T> { public readonly T Arg; public MyCollection(T arg, ReadOnlySpan<T> items) { Arg = arg; } IEnumerator<T> IEnumerable<T>.GetEnumerator() => null; IEnumerator IEnumerable.GetEnumerator() => null; } class MyBuilder { public static MyCollection<T> Create<T>(ReadOnlySpan<T> items, T arg = default) => new(arg, items); } """; string sourceB = """ using System; class Program { static void Main() { Console.WriteLine(EmptyArgs<int>().Arg); Console.WriteLine(NonEmptyArgs(2).Arg); Console.WriteLine(Params(3, 4).Arg); } static MyCollection<T> EmptyArgs<T>() => [with()]; static MyCollection<T> NonEmptyArgs<T>(T t) => [with(t)]; static MyCollection<T> Params<T>(params MyCollection<T> c) => c; } """; var comp = CreateCompilation( [sourceA, sourceB], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (8,27): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // Console.WriteLine(Params(3, 4).Arg); Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "Params(3, 4)").WithArguments("Create", "T", "MyCollection<T>").WithLocation(8, 27), // (10,46): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // static MyCollection<T> EmptyArgs<T>() => [with()]; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[with()]").WithArguments("Create", "T", "MyCollection<T>").WithLocation(10, 46), // (11,52): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // static MyCollection<T> NonEmptyArgs<T>(T t) => [with(t)]; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[with(t)]").WithArguments("Create", "T", "MyCollection<T>").WithLocation(11, 52), // (12,38): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // static MyCollection<T> Params<T>(params MyCollection<T> c) => c; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "params MyCollection<T> c").WithArguments("Create", "T", "MyCollection<T>").WithLocation(12, 38)); } [Fact] public void CollectionBuilder_OptionalParameter_A() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyCollection<T> : IEnumerable<T> { public readonly T Arg; public MyCollection(T arg, ReadOnlySpan<T> items) { Arg = arg; } IEnumerator<T> IEnumerable<T>.GetEnumerator() => null; IEnumerator IEnumerable.GetEnumerator() => null; } class MyBuilder { public static MyCollection<T> Create<T>(T arg = default, ReadOnlySpan<T> items = default) => new(arg, items); } """; string sourceB = """ using System; class Program { static void Main() { Console.WriteLine(EmptyArgs<int>().Arg); Console.WriteLine(NonEmptyArgs(2).Arg); Console.WriteLine(Params(3, 4).Arg); } static MyCollection<T> EmptyArgs<T>() => [with()]; static MyCollection<T> NonEmptyArgs<T>(T t) => [with(t)]; static MyCollection<T> Params<T>(params MyCollection<T> c) => c; } """; var comp = CreateCompilation( [sourceA, sourceB], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (12,38): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // static MyCollection<T> Params<T>(params MyCollection<T> c) => c; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "params MyCollection<T> c").WithArguments("Create", "T", "MyCollection<T>").WithLocation(12, 38)); } [Fact] public void CollectionBuilder_ParamsParameter() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyCollection<T> : IEnumerable<T> { public readonly T[] Args; public MyCollection(ReadOnlySpan<T> items, T[] args) { Args = args; } IEnumerator<T> IEnumerable<T>.GetEnumerator() => null; IEnumerator IEnumerable.GetEnumerator() => null; } class MyBuilder { public static MyCollection<T> Create<T>(ReadOnlySpan<T> items, params T[] args) => new(items, args); } """; string sourceB = """ class Program { static void Main() { EmptyArgs<int>().Args.Report(); OneArg(1).Args.Report(); TwoArgs(2, 3).Args.Report(); MultipleArgs([4, 5]).Args.Report(); Params(6).Args.Report(); } static MyCollection<T> EmptyArgs<T>() => [with()]; static MyCollection<T> OneArg<T>(T t) => [with(t)]; static MyCollection<T> TwoArgs<T>(T x, T y) => [with(x, y)]; static MyCollection<T> MultipleArgs<T>(T[] args) => [with(args)]; static MyCollection<T> Params<T>(params MyCollection<T> c) => c; } """; var comp = CreateCompilation( [sourceA, sourceB, s_collectionExtensions], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (9,9): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // Params(6).Args.Report(); Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "Params(6)").WithArguments("Create", "T", "MyCollection<T>").WithLocation(9, 9), // (11,46): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // static MyCollection<T> EmptyArgs<T>() => [with()]; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[with()]").WithArguments("Create", "T", "MyCollection<T>").WithLocation(11, 46), // (12,46): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // static MyCollection<T> OneArg<T>(T t) => [with(t)]; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[with(t)]").WithArguments("Create", "T", "MyCollection<T>").WithLocation(12, 46), // (13,52): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // static MyCollection<T> TwoArgs<T>(T x, T y) => [with(x, y)]; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[with(x, y)]").WithArguments("Create", "T", "MyCollection<T>").WithLocation(13, 52), // (14,57): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // static MyCollection<T> MultipleArgs<T>(T[] args) => [with(args)]; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[with(args)]").WithArguments("Create", "T", "MyCollection<T>").WithLocation(14, 57), // (15,38): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // static MyCollection<T> Params<T>(params MyCollection<T> c) => c; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "params MyCollection<T> c").WithArguments("Create", "T", "MyCollection<T>").WithLocation(15, 38)); } [Fact] public void CollectionBuilder_ImplicitParameter_Optional() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] struct MyCollection<T> : IEnumerable<T> { private readonly List<T> _list; internal MyCollection(ReadOnlySpan<T> items) { _list = new(items.ToArray()); } IEnumerator<T> IEnumerable<T>.GetEnumerator() => _list.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => _list.GetEnumerator(); } class MyBuilder { public static MyCollection<T> Create<T>(ReadOnlySpan<T> items = default) => new(items); } """; string sourceB1 = """ class Program { static void Main() { MyCollection<int> c; c = []; c.Report(); c = [1, 2, 3]; c.Report(); c = [with(), 4]; c.Report(); F(5, 6); } static void F<T>(params MyCollection<T> c) { c.Report(); } } """; var verifier = CompileAndVerify( [sourceA, sourceB1, s_collectionExtensions], targetFramework: TargetFramework.Net80, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("[], [1, 2, 3], [4], [5, 6], ")); verifier.VerifyDiagnostics(); string sourceB2 = """ class Program { static void Main() { MyCollection<int> c; c = [with(1)]; c = [with(2), 3]; } } """; var comp = CreateCompilation([sourceA, sourceB2], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (6,13): error CS9405: No overload for method 'Create' takes 1 'with(...)' element arguments // c = [with(1)]; Diagnostic(ErrorCode.ERR_BadCollectionArgumentsArgCount, "with(1)").WithArguments("Create", "1").WithLocation(6, 14), // (7,13): error CS9405: No overload for method 'Create' takes 1 'with(...)' element arguments // c = [with(2), 3]; Diagnostic(ErrorCode.ERR_BadCollectionArgumentsArgCount, "with(2)").WithArguments("Create", "1").WithLocation(7, 14)); } [Fact] public void CollectionBuilder_ImplicitParameter_Params_01() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] struct MyCollection<T> : IEnumerable<T> { private readonly List<T> _list; internal MyCollection(ReadOnlySpan<T> items) { _list = new(items.ToArray()); } IEnumerator<T> IEnumerable<T>.GetEnumerator() => _list.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => _list.GetEnumerator(); } class MyBuilder { public static MyCollection<T> Create<T>(params ReadOnlySpan<T> items) => new(items); } """; string sourceB1 = """ class Program { static void Main() { MyCollection<int> c; c = []; c.Report(); c = [1, 2, 3]; c.Report(); c = [with(), 4]; c.Report(); F(5, 6); } static void F<T>(params MyCollection<T> c) { c.Report(); } } """; var verifier = CompileAndVerify( [sourceA, sourceB1, s_collectionExtensions], targetFramework: TargetFramework.Net80, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("[], [1, 2, 3], [4], [5, 6], ")); verifier.VerifyDiagnostics(); string sourceB2 = """ class Program { static void Main() { MyCollection<int> c; c = [with(1)]; c = [with(2), 3]; } } """; var comp = CreateCompilation([sourceA, sourceB2], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (6,13): error CS9405: No overload for method 'Create' takes 1 'with(...)' element arguments // c = [with(1)]; Diagnostic(ErrorCode.ERR_BadCollectionArgumentsArgCount, "with(1)").WithArguments("Create", "1").WithLocation(6, 14), // (7,13): error CS9405: No overload for method 'Create' takes 1 'with(...)' element arguments // c = [with(2), 3]; Diagnostic(ErrorCode.ERR_BadCollectionArgumentsArgCount, "with(2)").WithArguments("Create", "1").WithLocation(7, 14)); } [Fact] public void CollectionBuilder_ImplicitParameter_Params_02() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] struct MyCollection<T> : IEnumerable<T> { private readonly List<T> _list; internal MyCollection(ReadOnlySpan<T> items) { _list = new(items.ToArray()); } IEnumerator<T> IEnumerable<T>.GetEnumerator() => _list.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => _list.GetEnumerator(); } class MyBuilder { public static MyCollection<T> Create<T>(params ReadOnlySpan<T> items) => new(items); } """; string sourceB = """ using System; class MyItem { public static implicit operator MyItem(ReadOnlySpan<MyItem> items) => new(); } class Program { static void Main() { MyItem x = new(); MyItem y = new(); MyCollection<MyItem> c; c = []; c = [x, y]; c = [with(x)]; c = [with(x), y]; c = [with(), x, y]; } } """; var comp = CreateCompilation([sourceA, sourceB], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (15,14): error CS9405: No overload for method 'Create' takes 1 'with(...)' element arguments // c = [with(x)]; Diagnostic(ErrorCode.ERR_BadCollectionArgumentsArgCount, "with(x)").WithArguments("Create", "1").WithLocation(15, 14), // (16,14): error CS9405: No overload for method 'Create' takes 1 'with(...)' element arguments // c = [with(x), y]; Diagnostic(ErrorCode.ERR_BadCollectionArgumentsArgCount, "with(x)").WithArguments("Create", "1").WithLocation(16, 14)); } // C#7.3 feature ImprovedOverloadCandidates drops candidates with constraint violations // (see OverloadResolution.RemoveConstraintViolations()) which allows constructing // MyCollection<T> and MyCollection<U> with different factory methods. [Fact] public void CollectionBuilder_MultipleBuilderMethods_GenericConstraints_ClassAndStruct() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyCollection<T> : IEnumerable<T> { private readonly List<T> _items; public MyCollection(ReadOnlySpan<T> items) { _items = new(items.ToArray()); } public MyCollection(T arg, ReadOnlySpan<T> items) { _items = new(); _items.Add(arg); _items.AddRange(items.ToArray()); } public IEnumerator<T> GetEnumerator() => _items.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } class MyBuilder { public static MyCollection<T> Create<T>(ReadOnlySpan<T> items) where T : class => new(items); public static MyCollection<T> Create<T>(ReadOnlySpan<T> items, T arg = default) where T : struct => new(arg, items); } """; string sourceB1 = """ class Program { static MyCollection<T> NoConstraints<T>(T x, T y) => [x, y]; } """; var comp = CreateCompilation([sourceA, sourceB1], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (3,58): error CS0452: The type 'T' must be a reference type in order to use it as parameter 'T' in the generic type or method 'MyBuilder.Create<T>(ReadOnlySpan<T>)' // static MyCollection<T> NoConstraints<T>(T x, T y) => [x, y]; Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "[x, y]").WithArguments("MyBuilder.Create<T>(System.ReadOnlySpan<T>)", "T", "T").WithLocation(3, 58)); string sourceB2 = """ class Program { static MyCollection<T> NoConstraints<T>(T x, T y) => NoConstraintsParams(x, y); static MyCollection<T> NoConstraintsParams<T>(params MyCollection<T> c) => c; } """; comp = CreateCompilation([sourceA, sourceB2], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (3,58): error CS0452: The type 'T' must be a reference type in order to use it as parameter 'T' in the generic type or method 'MyBuilder.Create<T>(ReadOnlySpan<T>)' // static MyCollection<T> NoConstraints<T>(T x, T y) => NoConstraintsParams(x, y); Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "NoConstraintsParams(x, y)").WithArguments("MyBuilder.Create<T>(System.ReadOnlySpan<T>)", "T", "T").WithLocation(3, 58), // (4,51): error CS0452: The type 'T' must be a reference type in order to use it as parameter 'T' in the generic type or method 'MyBuilder.Create<T>(ReadOnlySpan<T>)' // static MyCollection<T> NoConstraintsParams<T>(params MyCollection<T> c) => c; Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "params MyCollection<T> c").WithArguments("MyBuilder.Create<T>(System.ReadOnlySpan<T>)", "T", "T").WithLocation(4, 51)); string sourceB3 = """ class Program { static void Main() { StructConstraint(3, 4).Report(); ClassConstraint((object)5, 6).Report(); } static MyCollection<T> StructConstraint<T>(T x, T y) where T : struct => [x, y]; static MyCollection<T> ClassConstraint<T>(T x, T y) where T : class => [x, y]; } """; comp = CreateCompilation( [sourceA, sourceB3, s_collectionExtensions], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (8,78): error CS0452: The type 'T' must be a reference type in order to use it as parameter 'T' in the generic type or method 'MyBuilder.Create<T>(ReadOnlySpan<T>)' // static MyCollection<T> StructConstraint<T>(T x, T y) where T : struct => [x, y]; Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "[x, y]").WithArguments("MyBuilder.Create<T>(System.ReadOnlySpan<T>)", "T", "T").WithLocation(8, 78)); string sourceB4 = """ class Program { static void Main() { StructConstraint(3, 4).Report(); ClassConstraint((object)5, 6).Report(); } static MyCollection<T> StructConstraint<T>(T x, T y) where T : struct => StructConstraintParams(x, y); static MyCollection<T> ClassConstraint<T>(T x, T y) where T : class => ClassConstraintParams(x, y); static MyCollection<T> StructConstraintParams<T>(params MyCollection<T> c) where T : struct => c; static MyCollection<T> ClassConstraintParams<T>(params MyCollection<T> c) where T : class => c; } """; comp = CreateCompilation( [sourceA, sourceB4, s_collectionExtensions], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (8,78): error CS0452: The type 'T' must be a reference type in order to use it as parameter 'T' in the generic type or method 'MyBuilder.Create<T>(ReadOnlySpan<T>)' // static MyCollection<T> StructConstraint<T>(T x, T y) where T : struct => StructConstraintParams(x, y); Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "StructConstraintParams(x, y)").WithArguments("MyBuilder.Create<T>(System.ReadOnlySpan<T>)", "T", "T").WithLocation(8, 78), // (10,54): error CS0452: The type 'T' must be a reference type in order to use it as parameter 'T' in the generic type or method 'MyBuilder.Create<T>(ReadOnlySpan<T>)' // static MyCollection<T> StructConstraintParams<T>(params MyCollection<T> c) where T : struct => c; Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "params MyCollection<T> c").WithArguments("MyBuilder.Create<T>(System.ReadOnlySpan<T>)", "T", "T").WithLocation(10, 54)); } [Fact] public void CollectionBuilder_MultipleBuilderMethods_GenericConstraints_ClassAndStruct_A() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyCollection<T> : IEnumerable<T> { private readonly List<T> _items; public MyCollection(ReadOnlySpan<T> items) { _items = new(items.ToArray()); } public MyCollection(T arg, ReadOnlySpan<T> items) { _items = new(); _items.Add(arg); _items.AddRange(items.ToArray()); } public IEnumerator<T> GetEnumerator() => _items.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } class MyBuilder { public static MyCollection<T> Create<T>(ReadOnlySpan<T> items) where T : class => new(items); public static MyCollection<T> Create<T>(T arg = default, ReadOnlySpan<T> items) where T : struct => new(arg, items); } """; string sourceB1 = """ class Program { static MyCollection<T> NoConstraints<T>(T x, T y) => [x, y]; } """; var comp = CreateCompilation([sourceA, sourceB1], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (3,58): error CS0452: The type 'T' must be a reference type in order to use it as parameter 'T' in the generic type or method 'MyBuilder.Create<T>(ReadOnlySpan<T>)' // static MyCollection<T> NoConstraints<T>(T x, T y) => [x, y]; Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "[x, y]").WithArguments("MyBuilder.Create<T>(System.ReadOnlySpan<T>)", "T", "T").WithLocation(3, 58), // (25,83): error CS1737: Optional parameters must appear after all required parameters // public static MyCollection<T> Create<T>(T arg = default, ReadOnlySpan<T> items) where T : struct => new(arg, items); Diagnostic(ErrorCode.ERR_DefaultValueBeforeRequiredValue, ")").WithLocation(25, 83)); string sourceB2 = """ class Program { static MyCollection<T> NoConstraints<T>(T x, T y) => NoConstraintsParams(x, y); static MyCollection<T> NoConstraintsParams<T>(params MyCollection<T> c) => c; } """; comp = CreateCompilation([sourceA, sourceB2], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (3,58): error CS0452: The type 'T' must be a reference type in order to use it as parameter 'T' in the generic type or method 'MyBuilder.Create<T>(ReadOnlySpan<T>)' // static MyCollection<T> NoConstraints<T>(T x, T y) => NoConstraintsParams(x, y); Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "NoConstraintsParams(x, y)").WithArguments("MyBuilder.Create<T>(System.ReadOnlySpan<T>)", "T", "T").WithLocation(3, 58), // (4,51): error CS0452: The type 'T' must be a reference type in order to use it as parameter 'T' in the generic type or method 'MyBuilder.Create<T>(ReadOnlySpan<T>)' // static MyCollection<T> NoConstraintsParams<T>(params MyCollection<T> c) => c; Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "params MyCollection<T> c").WithArguments("MyBuilder.Create<T>(System.ReadOnlySpan<T>)", "T", "T").WithLocation(4, 51), // (25,83): error CS1737: Optional parameters must appear after all required parameters // public static MyCollection<T> Create<T>(T arg = default, ReadOnlySpan<T> items) where T : struct => new(arg, items); Diagnostic(ErrorCode.ERR_DefaultValueBeforeRequiredValue, ")").WithLocation(25, 83)); string sourceB3 = """ class Program { static void Main() { StructConstraint(3, 4).Report(); ClassConstraint((object)5, 6).Report(); } static MyCollection<T> StructConstraint<T>(T x, T y) where T : struct => [x, y]; static MyCollection<T> ClassConstraint<T>(T x, T y) where T : class => [x, y]; } """; comp = CreateCompilation( [sourceA, sourceB3, s_collectionExtensions], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (8,78): error CS0452: The type 'T' must be a reference type in order to use it as parameter 'T' in the generic type or method 'MyBuilder.Create<T>(ReadOnlySpan<T>)' // static MyCollection<T> StructConstraint<T>(T x, T y) where T : struct => [x, y]; Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "[x, y]").WithArguments("MyBuilder.Create<T>(System.ReadOnlySpan<T>)", "T", "T").WithLocation(8, 78), // (25,83): error CS1737: Optional parameters must appear after all required parameters // public static MyCollection<T> Create<T>(T arg = default, ReadOnlySpan<T> items) where T : struct => new(arg, items); Diagnostic(ErrorCode.ERR_DefaultValueBeforeRequiredValue, ")").WithLocation(25, 83)); string sourceB4 = """ class Program { static void Main() { StructConstraint(3, 4).Report(); ClassConstraint((object)5, 6).Report(); } static MyCollection<T> StructConstraint<T>(T x, T y) where T : struct => StructConstraintParams(x, y); static MyCollection<T> ClassConstraint<T>(T x, T y) where T : class => ClassConstraintParams(x, y); static MyCollection<T> StructConstraintParams<T>(params MyCollection<T> c) where T : struct => c; static MyCollection<T> ClassConstraintParams<T>(params MyCollection<T> c) where T : class => c; } """; comp = CreateCompilation( [sourceA, sourceB4, s_collectionExtensions], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (8,78): error CS0452: The type 'T' must be a reference type in order to use it as parameter 'T' in the generic type or method 'MyBuilder.Create<T>(ReadOnlySpan<T>)' // static MyCollection<T> StructConstraint<T>(T x, T y) where T : struct => StructConstraintParams(x, y); Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "StructConstraintParams(x, y)").WithArguments("MyBuilder.Create<T>(System.ReadOnlySpan<T>)", "T", "T").WithLocation(8, 78), // (10,54): error CS0452: The type 'T' must be a reference type in order to use it as parameter 'T' in the generic type or method 'MyBuilder.Create<T>(ReadOnlySpan<T>)' // static MyCollection<T> StructConstraintParams<T>(params MyCollection<T> c) where T : struct => c; Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "params MyCollection<T> c").WithArguments("MyBuilder.Create<T>(System.ReadOnlySpan<T>)", "T", "T").WithLocation(10, 54), // (25,83): error CS1737: Optional parameters must appear after all required parameters // public static MyCollection<T> Create<T>(T arg = default, ReadOnlySpan<T> items) where T : struct => new(arg, items); Diagnostic(ErrorCode.ERR_DefaultValueBeforeRequiredValue, ")").WithLocation(25, 83)); } [Fact] public void CollectionBuilder_MultipleBuilderMethods_GenericConstraints_NoneAndClass() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyCollection<T> : IEnumerable<T> { private readonly List<T> _items; public MyCollection(ReadOnlySpan<T> items) { _items = new(items.ToArray()); } public MyCollection(T arg, ReadOnlySpan<T> items) { _items = new(); _items.Add(arg); _items.AddRange(items.ToArray()); } public IEnumerator<T> GetEnumerator() => _items.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } class MyBuilder { public static MyCollection<T> Create<T>(ReadOnlySpan<T> items) => new(items); public static MyCollection<T> Create<T>(ReadOnlySpan<T> items, T arg = default) where T : class => new(arg, items); } """; string sourceB1 = """ class Program { static void Main() { NoConstraints(1, 2).Report(); StructConstraint(3, 4).Report(); ClassConstraint((object)5, 6).Report(); } static MyCollection<T> NoConstraints<T>(T x, T y) => [x, y]; static MyCollection<T> StructConstraint<T>(T x, T y) where T : struct => [x, y]; static MyCollection<T> ClassConstraint<T>(T x, T y) where T : class => [x, y]; } """; var verifier = CompileAndVerify( [sourceA, sourceB1, s_collectionExtensions], targetFramework: TargetFramework.Net80, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("[1, 2], [3, 4], [5, 6], ")); verifier.VerifyDiagnostics(); string expectedIL = """ { // Code size 50 (0x32) .maxstack 2 .locals init (<>y__InlineArray2<T> V_0) IL_0000: ldloca.s V_0 IL_0002: initobj "<>y__InlineArray2<T>" IL_0008: ldloca.s V_0 IL_000a: ldc.i4.0 IL_000b: call "ref T <PrivateImplementationDetails>.InlineArrayElementRef<<>y__InlineArray2<T>, T>(ref <>y__InlineArray2<T>, int)" IL_0010: ldarg.0 IL_0011: stobj "T" IL_0016: ldloca.s V_0 IL_0018: ldc.i4.1 IL_0019: call "ref T <PrivateImplementationDetails>.InlineArrayElementRef<<>y__InlineArray2<T>, T>(ref <>y__InlineArray2<T>, int)" IL_001e: ldarg.1 IL_001f: stobj "T" IL_0024: ldloca.s V_0 IL_0026: ldc.i4.2 IL_0027: call "System.ReadOnlySpan<T> <PrivateImplementationDetails>.InlineArrayAsReadOnlySpan<<>y__InlineArray2<T>, T>(in <>y__InlineArray2<T>, int)" IL_002c: call "MyCollection<T> MyBuilder.Create<T>(System.ReadOnlySpan<T>)" IL_0031: ret } """; verifier.VerifyIL("Program.NoConstraints<T>", expectedIL); verifier.VerifyIL("Program.StructConstraint<T>", expectedIL); verifier.VerifyIL("Program.ClassConstraint<T>", expectedIL); string sourceB2 = """ class Program { static void Main() { NoConstraints(1, 2).Report(); StructConstraint(3, 4).Report(); ClassConstraint((object)5, 6).Report(); } static MyCollection<T> NoConstraints<T>(T x, T y) => NoConstraintsParams(x, y); static MyCollection<T> StructConstraint<T>(T x, T y) where T : struct => StructConstraintParams(x, y); static MyCollection<T> ClassConstraint<T>(T x, T y) where T : class => ClassConstraintParams(x, y); static MyCollection<T> NoConstraintsParams<T>(params MyCollection<T> c) => c; static MyCollection<T> StructConstraintParams<T>(params MyCollection<T> c) where T : struct => c; static MyCollection<T> ClassConstraintParams<T>(params MyCollection<T> c) where T : class => c; } """; verifier = CompileAndVerify( [sourceA, sourceB2, s_collectionExtensions], targetFramework: TargetFramework.Net80, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("[1, 2], [3, 4], [5, 6], ")); verifier.VerifyDiagnostics(); expectedIL = """ { // Code size 55 (0x37) .maxstack 2 .locals init (<>y__InlineArray2<T> V_0) IL_0000: ldloca.s V_0 IL_0002: initobj "<>y__InlineArray2<T>" IL_0008: ldloca.s V_0 IL_000a: ldc.i4.0 IL_000b: call "ref T <PrivateImplementationDetails>.InlineArrayElementRef<<>y__InlineArray2<T>, T>(ref <>y__InlineArray2<T>, int)" IL_0010: ldarg.0 IL_0011: stobj "T" IL_0016: ldloca.s V_0 IL_0018: ldc.i4.1 IL_0019: call "ref T <PrivateImplementationDetails>.InlineArrayElementRef<<>y__InlineArray2<T>, T>(ref <>y__InlineArray2<T>, int)" IL_001e: ldarg.1 IL_001f: stobj "T" IL_0024: ldloca.s V_0 IL_0026: ldc.i4.2 IL_0027: call "System.ReadOnlySpan<T> <PrivateImplementationDetails>.InlineArrayAsReadOnlySpan<<>y__InlineArray2<T>, T>(in <>y__InlineArray2<T>, int)" IL_002c: call "MyCollection<T> MyBuilder.Create<T>(System.ReadOnlySpan<T>)" IL_0031: call "MyCollection<T> Program.NoConstraintsParams<T>(params MyCollection<T>)" IL_0036: ret } """; verifier.VerifyIL("Program.NoConstraints<T>", expectedIL); verifier.VerifyIL("Program.StructConstraint<T>", expectedIL.Replace("NoConstraintsParams", "StructConstraintParams")); verifier.VerifyIL("Program.ClassConstraint<T>", expectedIL.Replace("NoConstraintsParams", "ClassConstraintParams")); } [Fact] public void CollectionBuilder_MultipleBuilderMethods_GenericConstraints_NoneAndClass_A() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyCollection<T> : IEnumerable<T> { private readonly List<T> _items; public MyCollection(ReadOnlySpan<T> items) { _items = new(items.ToArray()); } public MyCollection(T arg, ReadOnlySpan<T> items) { _items = new(); _items.Add(arg); _items.AddRange(items.ToArray()); } public IEnumerator<T> GetEnumerator() => _items.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } class MyBuilder { public static MyCollection<T> Create<T>(ReadOnlySpan<T> items) => new(items); public static MyCollection<T> Create<T>(T arg = default, ReadOnlySpan<T> items = default) where T : class => new(arg, items); } """; string sourceB1 = """ class Program { static void Main() { NoConstraints(1, 2).Report(); StructConstraint(3, 4).Report(); ClassConstraint((object)5, 6).Report(); } static MyCollection<T> NoConstraints<T>(T x, T y) => [x, y]; static MyCollection<T> StructConstraint<T>(T x, T y) where T : struct => [x, y]; static MyCollection<T> ClassConstraint<T>(T x, T y) where T : class => [x, y]; } """; var verifier = CompileAndVerify( [sourceA, sourceB1, s_collectionExtensions], targetFramework: TargetFramework.Net80, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("[1, 2], [3, 4], [5, 6], ")); verifier.VerifyDiagnostics(); string expectedIL = """ { // Code size 50 (0x32) .maxstack 2 .locals init (<>y__InlineArray2<T> V_0) IL_0000: ldloca.s V_0 IL_0002: initobj "<>y__InlineArray2<T>" IL_0008: ldloca.s V_0 IL_000a: ldc.i4.0 IL_000b: call "ref T <PrivateImplementationDetails>.InlineArrayElementRef<<>y__InlineArray2<T>, T>(ref <>y__InlineArray2<T>, int)" IL_0010: ldarg.0 IL_0011: stobj "T" IL_0016: ldloca.s V_0 IL_0018: ldc.i4.1 IL_0019: call "ref T <PrivateImplementationDetails>.InlineArrayElementRef<<>y__InlineArray2<T>, T>(ref <>y__InlineArray2<T>, int)" IL_001e: ldarg.1 IL_001f: stobj "T" IL_0024: ldloca.s V_0 IL_0026: ldc.i4.2 IL_0027: call "System.ReadOnlySpan<T> <PrivateImplementationDetails>.InlineArrayAsReadOnlySpan<<>y__InlineArray2<T>, T>(in <>y__InlineArray2<T>, int)" IL_002c: call "MyCollection<T> MyBuilder.Create<T>(System.ReadOnlySpan<T>)" IL_0031: ret } """; verifier.VerifyIL("Program.NoConstraints<T>", expectedIL); verifier.VerifyIL("Program.StructConstraint<T>", expectedIL); verifier.VerifyIL("Program.ClassConstraint<T>", expectedIL); string sourceB2 = """ class Program { static void Main() { NoConstraints(1, 2).Report(); StructConstraint(3, 4).Report(); ClassConstraint((object)5, 6).Report(); } static MyCollection<T> NoConstraints<T>(T x, T y) => NoConstraintsParams(x, y); static MyCollection<T> StructConstraint<T>(T x, T y) where T : struct => StructConstraintParams(x, y); static MyCollection<T> ClassConstraint<T>(T x, T y) where T : class => ClassConstraintParams(x, y); static MyCollection<T> NoConstraintsParams<T>(params MyCollection<T> c) => c; static MyCollection<T> StructConstraintParams<T>(params MyCollection<T> c) where T : struct => c; static MyCollection<T> ClassConstraintParams<T>(params MyCollection<T> c) where T : class => c; } """; verifier = CompileAndVerify( [sourceA, sourceB2, s_collectionExtensions], targetFramework: TargetFramework.Net80, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("[1, 2], [3, 4], [5, 6], ")); verifier.VerifyDiagnostics(); expectedIL = """ { // Code size 55 (0x37) .maxstack 2 .locals init (<>y__InlineArray2<T> V_0) IL_0000: ldloca.s V_0 IL_0002: initobj "<>y__InlineArray2<T>" IL_0008: ldloca.s V_0 IL_000a: ldc.i4.0 IL_000b: call "ref T <PrivateImplementationDetails>.InlineArrayElementRef<<>y__InlineArray2<T>, T>(ref <>y__InlineArray2<T>, int)" IL_0010: ldarg.0 IL_0011: stobj "T" IL_0016: ldloca.s V_0 IL_0018: ldc.i4.1 IL_0019: call "ref T <PrivateImplementationDetails>.InlineArrayElementRef<<>y__InlineArray2<T>, T>(ref <>y__InlineArray2<T>, int)" IL_001e: ldarg.1 IL_001f: stobj "T" IL_0024: ldloca.s V_0 IL_0026: ldc.i4.2 IL_0027: call "System.ReadOnlySpan<T> <PrivateImplementationDetails>.InlineArrayAsReadOnlySpan<<>y__InlineArray2<T>, T>(in <>y__InlineArray2<T>, int)" IL_002c: call "MyCollection<T> MyBuilder.Create<T>(System.ReadOnlySpan<T>)" IL_0031: call "MyCollection<T> Program.NoConstraintsParams<T>(params MyCollection<T>)" IL_0036: ret } """; verifier.VerifyIL("Program.NoConstraints<T>", expectedIL); verifier.VerifyIL("Program.StructConstraint<T>", expectedIL.Replace("NoConstraintsParams", "StructConstraintParams")); verifier.VerifyIL("Program.ClassConstraint<T>", expectedIL.Replace("NoConstraintsParams", "ClassConstraintParams")); } [Fact] public void CollectionBuilder_MultipleBuilderMethods_GenericConstraints_StructAndNone() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyCollection<T> : IEnumerable<T> { private readonly List<T> _items; public MyCollection(ReadOnlySpan<T> items) { _items = new(items.ToArray()); } public MyCollection(T arg, ReadOnlySpan<T> items) { _items = new(); _items.Add(arg); _items.AddRange(items.ToArray()); } public IEnumerator<T> GetEnumerator() => _items.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } class MyBuilder { public static MyCollection<T> Create<T>(ReadOnlySpan<T> items) where T : struct => new(items); public static MyCollection<T> Create<T>(ReadOnlySpan<T> items, T arg = default) => new(arg, items); } """; string sourceB1 = """ class Program { static void Main() { NoConstraints(1, 2).Report(); StructConstraint(3, 4).Report(); ClassConstraint((object)5, 6).Report(); } static MyCollection<T> NoConstraints<T>(T x, T y) => [x, y]; static MyCollection<T> StructConstraint<T>(T x, T y) where T : struct => [x, y]; static MyCollection<T> ClassConstraint<T>(T x, T y) where T : class => [x, y]; } """; var comp = CreateCompilation( [sourceA, sourceB1, s_collectionExtensions], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (9,58): error CS0453: The type 'T' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'MyBuilder.Create<T>(ReadOnlySpan<T>)' // static MyCollection<T> NoConstraints<T>(T x, T y) => [x, y]; Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "[x, y]").WithArguments("MyBuilder.Create<T>(System.ReadOnlySpan<T>)", "T", "T").WithLocation(9, 58), // (11,76): error CS0453: The type 'T' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'MyBuilder.Create<T>(ReadOnlySpan<T>)' // static MyCollection<T> ClassConstraint<T>(T x, T y) where T : class => [x, y]; Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "[x, y]").WithArguments("MyBuilder.Create<T>(System.ReadOnlySpan<T>)", "T", "T").WithLocation(11, 76)); string sourceB2 = """ class Program { static void Main() { NoConstraints(1, 2).Report(); StructConstraint(3, 4).Report(); ClassConstraint((object)5, 6).Report(); } static MyCollection<T> NoConstraints<T>(T x, T y) => NoConstraintsParams(x, y); static MyCollection<T> StructConstraint<T>(T x, T y) where T : struct => StructConstraintParams(x, y); static MyCollection<T> ClassConstraint<T>(T x, T y) where T : class => ClassConstraintParams(x, y); static MyCollection<T> NoConstraintsParams<T>(params MyCollection<T> c) => c; static MyCollection<T> StructConstraintParams<T>(params MyCollection<T> c) where T : struct => c; static MyCollection<T> ClassConstraintParams<T>(params MyCollection<T> c) where T : class => c; } """; comp = CreateCompilation( [sourceA, sourceB2, s_collectionExtensions], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (9,58): error CS0453: The type 'T' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'MyBuilder.Create<T>(ReadOnlySpan<T>)' // static MyCollection<T> NoConstraints<T>(T x, T y) => NoConstraintsParams(x, y); Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "NoConstraintsParams(x, y)").WithArguments("MyBuilder.Create<T>(System.ReadOnlySpan<T>)", "T", "T").WithLocation(9, 58), // (11,76): error CS0453: The type 'T' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'MyBuilder.Create<T>(ReadOnlySpan<T>)' // static MyCollection<T> ClassConstraint<T>(T x, T y) where T : class => ClassConstraintParams(x, y); Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "ClassConstraintParams(x, y)").WithArguments("MyBuilder.Create<T>(System.ReadOnlySpan<T>)", "T", "T").WithLocation(11, 76), // (12,51): error CS0453: The type 'T' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'MyBuilder.Create<T>(ReadOnlySpan<T>)' // static MyCollection<T> NoConstraintsParams<T>(params MyCollection<T> c) => c; Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "params MyCollection<T> c").WithArguments("MyBuilder.Create<T>(System.ReadOnlySpan<T>)", "T", "T").WithLocation(12, 51), // (14,53): error CS0453: The type 'T' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'MyBuilder.Create<T>(ReadOnlySpan<T>)' // static MyCollection<T> ClassConstraintParams<T>(params MyCollection<T> c) where T : class => c; Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "params MyCollection<T> c").WithArguments("MyBuilder.Create<T>(System.ReadOnlySpan<T>)", "T", "T").WithLocation(14, 53)); } [Fact] public void CollectionBuilder_MultipleBuilderMethods_GenericConstraints_StructAndNone_A() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyCollection<T> : IEnumerable<T> { private readonly List<T> _items; public MyCollection(ReadOnlySpan<T> items) { _items = new(items.ToArray()); } public MyCollection(T arg, ReadOnlySpan<T> items) { _items = new(); _items.Add(arg); _items.AddRange(items.ToArray()); } public IEnumerator<T> GetEnumerator() => _items.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } class MyBuilder { public static MyCollection<T> Create<T>(ReadOnlySpan<T> items) where T : struct => new(items); public static MyCollection<T> Create<T>(T arg = default, ReadOnlySpan<T> items = default) => new(arg, items); } """; string sourceB1 = """ class Program { static void Main() { NoConstraints(1, 2).Report(); StructConstraint(3, 4).Report(); ClassConstraint((object)5, 6).Report(); } static MyCollection<T> NoConstraints<T>(T x, T y) => [x, y]; static MyCollection<T> StructConstraint<T>(T x, T y) where T : struct => [x, y]; static MyCollection<T> ClassConstraint<T>(T x, T y) where T : class => [x, y]; } """; var comp = CreateCompilation( [sourceA, sourceB1, s_collectionExtensions], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (9,58): error CS0453: The type 'T' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'MyBuilder.Create<T>(ReadOnlySpan<T>)' // static MyCollection<T> NoConstraints<T>(T x, T y) => [x, y]; Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "[x, y]").WithArguments("MyBuilder.Create<T>(System.ReadOnlySpan<T>)", "T", "T").WithLocation(9, 58), // (11,76): error CS0453: The type 'T' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'MyBuilder.Create<T>(ReadOnlySpan<T>)' // static MyCollection<T> ClassConstraint<T>(T x, T y) where T : class => [x, y]; Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "[x, y]").WithArguments("MyBuilder.Create<T>(System.ReadOnlySpan<T>)", "T", "T").WithLocation(11, 76)); string sourceB2 = """ class Program { static void Main() { NoConstraints(1, 2).Report(); StructConstraint(3, 4).Report(); ClassConstraint((object)5, 6).Report(); } static MyCollection<T> NoConstraints<T>(T x, T y) => NoConstraintsParams(x, y); static MyCollection<T> StructConstraint<T>(T x, T y) where T : struct => StructConstraintParams(x, y); static MyCollection<T> ClassConstraint<T>(T x, T y) where T : class => ClassConstraintParams(x, y); static MyCollection<T> NoConstraintsParams<T>(params MyCollection<T> c) => c; static MyCollection<T> StructConstraintParams<T>(params MyCollection<T> c) where T : struct => c; static MyCollection<T> ClassConstraintParams<T>(params MyCollection<T> c) where T : class => c; } """; comp = CreateCompilation( [sourceA, sourceB2, s_collectionExtensions], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (9,58): error CS0453: The type 'T' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'MyBuilder.Create<T>(ReadOnlySpan<T>)' // static MyCollection<T> NoConstraints<T>(T x, T y) => NoConstraintsParams(x, y); Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "NoConstraintsParams(x, y)").WithArguments("MyBuilder.Create<T>(System.ReadOnlySpan<T>)", "T", "T").WithLocation(9, 58), // (11,76): error CS0453: The type 'T' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'MyBuilder.Create<T>(ReadOnlySpan<T>)' // static MyCollection<T> ClassConstraint<T>(T x, T y) where T : class => ClassConstraintParams(x, y); Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "ClassConstraintParams(x, y)").WithArguments("MyBuilder.Create<T>(System.ReadOnlySpan<T>)", "T", "T").WithLocation(11, 76), // (12,51): error CS0453: The type 'T' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'MyBuilder.Create<T>(ReadOnlySpan<T>)' // static MyCollection<T> NoConstraintsParams<T>(params MyCollection<T> c) => c; Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "params MyCollection<T> c").WithArguments("MyBuilder.Create<T>(System.ReadOnlySpan<T>)", "T", "T").WithLocation(12, 51), // (14,53): error CS0453: The type 'T' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'MyBuilder.Create<T>(ReadOnlySpan<T>)' // static MyCollection<T> ClassConstraintParams<T>(params MyCollection<T> c) where T : class => c; Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "params MyCollection<T> c").WithArguments("MyBuilder.Create<T>(System.ReadOnlySpan<T>)", "T", "T").WithLocation(14, 53)); } [Fact] public void CollectionBuilder_NamedParameter() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] struct MyCollection<T> : IEnumerable<T> { private readonly List<T> _list; internal MyCollection(ReadOnlySpan<T> items, T x, T y) { _list = new(); _list.Add(x); _list.Add(y); _list.AddRange(items.ToArray()); } IEnumerator<T> IEnumerable<T>.GetEnumerator() => _list.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => _list.GetEnumerator(); } class MyBuilder { public static MyCollection<T> Create<T>(ReadOnlySpan<T> items) => default; public static MyCollection<T> Create<T>(ReadOnlySpan<T> items, T x = default, T y = default) => new(items, x, y); } """; string sourceB = """ MyCollection<int> c; c = [with(x: 1), 2, 3]; c.Report(); c = [with(y: 4), 5]; c.Report(); c = [with(y: 6, x: 7), 8]; c.Report(); """; var comp = CreateCompilation( [sourceA, sourceB, s_collectionExtensions], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (2,11): error CS1739: The best overload for 'Create' does not have a parameter named 'x' // c = [with(x: 1), 2, 3]; Diagnostic(ErrorCode.ERR_BadNamedArgument, "x").WithArguments("Create", "x").WithLocation(2, 11), // (4,11): error CS1739: The best overload for 'Create' does not have a parameter named 'y' // c = [with(y: 4), 5]; Diagnostic(ErrorCode.ERR_BadNamedArgument, "y").WithArguments("Create", "y").WithLocation(4, 11), // (6,11): error CS1739: The best overload for 'Create' does not have a parameter named 'y' // c = [with(y: 6, x: 7), 8]; Diagnostic(ErrorCode.ERR_BadNamedArgument, "y").WithArguments("Create", "y").WithLocation(6, 11)); } [Fact] public void CollectionBuilder_NamedParameter_A() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] struct MyCollection<T> : IEnumerable<T> { private readonly List<T> _list; internal MyCollection(ReadOnlySpan<T> items, T x, T y) { _list = new(); _list.Add(x); _list.Add(y); _list.AddRange(items.ToArray()); } IEnumerator<T> IEnumerable<T>.GetEnumerator() => _list.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => _list.GetEnumerator(); } class MyBuilder { public static MyCollection<T> Create<T>(ReadOnlySpan<T> items) => default; public static MyCollection<T> Create<T>(T x = default, T y = default, ReadOnlySpan<T> items = default) => new(items, x, y); } """; string sourceB = """ MyCollection<int> c; c = [with(x: 1), 2, 3]; c.Report(); c = [with(y: 4), 5]; c.Report(); c = [with(y: 6, x: 7), 8]; c.Report(); """; var verifier = CompileAndVerify( [sourceA, sourceB, s_collectionExtensions], targetFramework: TargetFramework.Net80, expectedOutput: IncludeExpectedOutput("[1, 0, 2, 3], [0, 4, 5], [7, 6, 8], "), verify: Verification.FailsPEVerify); verifier.VerifyDiagnostics(); } [Fact] public void CollectionBuilder_RefParameter() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] struct MyCollection<T> : IEnumerable<T> { private readonly List<T> _list; internal MyCollection(ReadOnlySpan<T> items, T arg) { _list = new(items.ToArray()); _list.Add(arg); } IEnumerator<T> IEnumerable<T>.GetEnumerator() => _list.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => _list.GetEnumerator(); } class MyBuilder { public static MyCollection<T> Create<T>(ReadOnlySpan<T> items) => throw null; public static MyCollection<T> Create<T>(ReadOnlySpan<T> items, ref T x) => new(items, x); } """; string sourceB1 = """ #pragma warning disable 219 // variable assigned but never used MyCollection<int> c; int x = 1; ref int r = ref x; c = [with(ref x)]; c.Report(); x = 2; c = [with(ref r)]; c.Report(); """; var comp = CreateCompilation( [sourceA, sourceB1, s_collectionExtensions], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (5,6): error CS9405: No overload for method 'Create' takes 1 'with(...)' element arguments // c = [with(ref x)]; Diagnostic(ErrorCode.ERR_BadCollectionArgumentsArgCount, "with(ref x)").WithArguments("Create", "1").WithLocation(5, 6), // (8,6): error CS9405: No overload for method 'Create' takes 1 'with(...)' element arguments // c = [with(ref r)]; Diagnostic(ErrorCode.ERR_BadCollectionArgumentsArgCount, "with(ref r)").WithArguments("Create", "1").WithLocation(8, 6)); string sourceB2 = """ #pragma warning disable 219 // variable assigned but never used MyCollection<int> c; int x = 1; ref readonly int ro = ref x; c = [with(0)]; c = [with(x)]; c = [with(in x)]; c = [with(ref ro)]; c = [with(out x)]; """; comp = CreateCompilation([sourceA, sourceB2], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (5,6): error CS9405: No overload for method 'Create' takes 1 'with(...)' element arguments // c = [with(0)]; Diagnostic(ErrorCode.ERR_BadCollectionArgumentsArgCount, "with(0)").WithArguments("Create", "1").WithLocation(5, 6), // (6,6): error CS9405: No overload for method 'Create' takes 1 'with(...)' element arguments // c = [with(x)]; Diagnostic(ErrorCode.ERR_BadCollectionArgumentsArgCount, "with(x)").WithArguments("Create", "1").WithLocation(6, 6), // (7,6): error CS9405: No overload for method 'Create' takes 1 'with(...)' element arguments // c = [with(in x)]; Diagnostic(ErrorCode.ERR_BadCollectionArgumentsArgCount, "with(in x)").WithArguments("Create", "1").WithLocation(7, 6), // (8,15): error CS1510: A ref or out value must be an assignable variable // c = [with(ref ro)]; Diagnostic(ErrorCode.ERR_RefLvalueExpected, "ro").WithLocation(8, 15), // (9,6): error CS9405: No overload for method 'Create' takes 1 'with(...)' element arguments // c = [with(out x)]; Diagnostic(ErrorCode.ERR_BadCollectionArgumentsArgCount, "with(out x)").WithArguments("Create", "1").WithLocation(9, 6)); } [Fact] public void CollectionBuilder_RefParameter_A() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] struct MyCollection<T> : IEnumerable<T> { private readonly List<T> _list; internal MyCollection(ReadOnlySpan<T> items, T arg) { _list = new(items.ToArray()); _list.Add(arg); } IEnumerator<T> IEnumerable<T>.GetEnumerator() => _list.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => _list.GetEnumerator(); } class MyBuilder { public static MyCollection<T> Create<T>(ReadOnlySpan<T> items) => throw null; public static MyCollection<T> Create<T>(ref T x, ReadOnlySpan<T> items) => new(items, x); } """; string sourceB1 = """ #pragma warning disable 219 // variable assigned but never used MyCollection<int> c; int x = 1; ref int r = ref x; c = [with(ref x)]; c.Report(); x = 2; c = [with(ref r)]; c.Report(); """; var verifier = CompileAndVerify( [sourceA, sourceB1, s_collectionExtensions], targetFramework: TargetFramework.Net80, expectedOutput: IncludeExpectedOutput("[1], [2], "), verify: Verification.FailsPEVerify); verifier.VerifyDiagnostics(); string sourceB2 = """ #pragma warning disable 219 // variable assigned but never used MyCollection<int> c; int x = 1; ref readonly int ro = ref x; c = [with(0)]; c = [with(x)]; c = [with(in x)]; c = [with(ref ro)]; c = [with(out x)]; """; var comp = CreateCompilation([sourceA, sourceB2], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (5,11): error CS1620: Argument 1 must be passed with the 'ref' keyword // c = [with(0)]; Diagnostic(ErrorCode.ERR_BadArgRef, "0").WithArguments("1", "ref").WithLocation(5, 11), // (6,11): error CS1620: Argument 1 must be passed with the 'ref' keyword // c = [with(x)]; Diagnostic(ErrorCode.ERR_BadArgRef, "x").WithArguments("1", "ref").WithLocation(6, 11), // (7,14): error CS1620: Argument 1 must be passed with the 'ref' keyword // c = [with(in x)]; Diagnostic(ErrorCode.ERR_BadArgRef, "x").WithArguments("1", "ref").WithLocation(7, 14), // (8,15): error CS1510: A ref or out value must be an assignable variable // c = [with(ref ro)]; Diagnostic(ErrorCode.ERR_RefLvalueExpected, "ro").WithLocation(8, 15), // (9,15): error CS1620: Argument 1 must be passed with the 'ref' keyword // c = [with(out x)]; Diagnostic(ErrorCode.ERR_BadArgRef, "x").WithArguments("1", "ref").WithLocation(9, 15)); } [Fact] public void CollectionBuilder_RefReadonlyParameter() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] struct MyCollection<T> : IEnumerable<T> { private readonly List<T> _list; internal MyCollection(ReadOnlySpan<T> items, T arg) { _list = new(items.ToArray()); _list.Add(arg); } IEnumerator<T> IEnumerable<T>.GetEnumerator() => _list.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => _list.GetEnumerator(); } class MyBuilder { public static MyCollection<T> Create<T>(ReadOnlySpan<T> items) => throw null; public static MyCollection<T> Create<T>(ReadOnlySpan<T> items, ref readonly T x) => new(items, x); } """; string sourceB1 = """ #pragma warning disable 219 // variable assigned but never used MyCollection<int> c; int x = 1; ref int r = ref x; ref readonly int ro = ref x; c = [with(0)]; c.Report(); c = [with(x)]; c.Report(); x = 2; c = [with(ref x)]; c.Report(); x = 3; c = [with(ref r)]; c.Report(); x = 4; c = [with(in ro)]; c.Report(); """; var comp = CreateCompilation( [sourceA, sourceB1, s_collectionExtensions], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (6,5): error CS9405: No overload for method 'Create' takes 1 'with(...)' element arguments // c = [with(0)]; Diagnostic(ErrorCode.ERR_BadCollectionArgumentsArgCount, "with(0)").WithArguments("Create", "1").WithLocation(6, 6), // (8,5): error CS9405: No overload for method 'Create' takes 1 'with(...)' element arguments // c = [with(x)]; Diagnostic(ErrorCode.ERR_BadCollectionArgumentsArgCount, "with(x)").WithArguments("Create", "1").WithLocation(8, 6), // (11,5): error CS9405: No overload for method 'Create' takes 1 'with(...)' element arguments // c = [with(ref x)]; Diagnostic(ErrorCode.ERR_BadCollectionArgumentsArgCount, "with(ref x)").WithArguments("Create", "1").WithLocation(11, 6), // (14,5): error CS9405: No overload for method 'Create' takes 1 'with(...)' element arguments // c = [with(ref r)]; Diagnostic(ErrorCode.ERR_BadCollectionArgumentsArgCount, "with(ref r)").WithArguments("Create", "1").WithLocation(14, 6), // (17,5): error CS9405: No overload for method 'Create' takes 1 'with(...)' element arguments // c = [with(in ro)]; Diagnostic(ErrorCode.ERR_BadCollectionArgumentsArgCount, "with(in ro)").WithArguments("Create", "1").WithLocation(17, 6)); string sourceB2 = """ #pragma warning disable 219 // variable assigned but never used MyCollection<int> c; int x = 1; ref readonly int ro = ref x; c = [with(in x)]; c = [with(ref ro)]; c = [with(out x)]; """; comp = CreateCompilation([sourceA, sourceB2], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (5,6): error CS9405: No overload for method 'Create' takes 1 'with(...)' element arguments // c = [with(in x)]; Diagnostic(ErrorCode.ERR_BadCollectionArgumentsArgCount, "with(in x)").WithArguments("Create", "1").WithLocation(5, 6), // (6,15): error CS1510: A ref or out value must be an assignable variable // c = [with(ref ro)]; Diagnostic(ErrorCode.ERR_RefLvalueExpected, "ro").WithLocation(6, 15), // (7,6): error CS9405: No overload for method 'Create' takes 1 'with(...)' element arguments // c = [with(out x)]; Diagnostic(ErrorCode.ERR_BadCollectionArgumentsArgCount, "with(out x)").WithArguments("Create", "1").WithLocation(7, 6)); } [Fact] public void CollectionBuilder_RefReadonlyParameter_A() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] struct MyCollection<T> : IEnumerable<T> { private readonly List<T> _list; internal MyCollection(ReadOnlySpan<T> items, T arg) { _list = new(items.ToArray()); _list.Add(arg); } IEnumerator<T> IEnumerable<T>.GetEnumerator() => _list.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => _list.GetEnumerator(); } class MyBuilder { public static MyCollection<T> Create<T>(ReadOnlySpan<T> items) => throw null; public static MyCollection<T> Create<T>(ref readonly T x, ReadOnlySpan<T> items) => new(items, x); } """; string sourceB1 = """ #pragma warning disable 219 // variable assigned but never used MyCollection<int> c; int x = 1; ref int r = ref x; ref readonly int ro = ref x; c = [with(0)]; c.Report(); c = [with(x)]; c.Report(); x = 2; c = [with(ref x)]; c.Report(); x = 3; c = [with(ref r)]; c.Report(); x = 4; c = [with(in ro)]; c.Report(); """; CompileAndVerify( [sourceA, sourceB1, s_collectionExtensions], targetFramework: TargetFramework.Net80, expectedOutput: IncludeExpectedOutput("[0], [1], [2], [3], [4], "), verify: Verification.FailsPEVerify).VerifyDiagnostics( // (6,11): warning CS9193: Argument 1 should be a variable because it is passed to a 'ref readonly' parameter // c = [with(0)]; Diagnostic(ErrorCode.WRN_RefReadonlyNotVariable, "0").WithArguments("1").WithLocation(6, 11), // (8,11): warning CS9192: Argument 1 should be passed with 'ref' or 'in' keyword // c = [with(x)]; Diagnostic(ErrorCode.WRN_ArgExpectedRefOrIn, "x").WithArguments("1").WithLocation(8, 11)); string sourceB2 = """ #pragma warning disable 219 // variable assigned but never used MyCollection<int> c; int x = 1; ref readonly int ro = ref x; c = [with(in x)]; c = [with(ref ro)]; c = [with(out x)]; """; var comp = CreateCompilation([sourceA, sourceB2], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (6,15): error CS1510: A ref or out value must be an assignable variable // c = [with(ref ro)]; Diagnostic(ErrorCode.ERR_RefLvalueExpected, "ro").WithLocation(6, 15), // (7,15): error CS1615: Argument 1 may not be passed with the 'out' keyword // c = [with(out x)]; Diagnostic(ErrorCode.ERR_BadArgExtraRef, "x").WithArguments("1", "out").WithLocation(7, 15)); } [Fact] public void CollectionBuilder_InParameter() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] struct MyCollection<T> : IEnumerable<T> { private readonly List<T> _list; internal MyCollection(ReadOnlySpan<T> items, T arg) { _list = new(items.ToArray()); _list.Add(arg); } IEnumerator<T> IEnumerable<T>.GetEnumerator() => _list.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => _list.GetEnumerator(); } class MyBuilder { public static MyCollection<T> Create<T>(ReadOnlySpan<T> items) => throw null; public static MyCollection<T> Create<T>(ReadOnlySpan<T> items, in T x) => new(items, x); } """; string sourceB1 = """ #pragma warning disable 219 // variable assigned but never used MyCollection<int> c; int x = 1; ref int r = ref x; ref readonly int ro = ref x; c = [with(0)]; c.Report(); c = [with(x)]; c.Report(); x = 2; c = [with(ref x)]; c.Report(); x = 3; c = [with(in x)]; c.Report(); x = 4; c = [with(in r)]; c.Report(); x = 5; c = [with(in ro)]; c.Report(); """; var comp = CreateCompilation([sourceA, sourceB1, s_collectionExtensions], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (6,6): error CS9405: No overload for method 'Create' takes 1 'with(...)' element arguments // c = [with(0)]; Diagnostic(ErrorCode.ERR_BadCollectionArgumentsArgCount, "with(0)").WithArguments("Create", "1").WithLocation(6, 6), // (8,6): error CS9405: No overload for method 'Create' takes 1 'with(...)' element arguments // c = [with(x)]; Diagnostic(ErrorCode.ERR_BadCollectionArgumentsArgCount, "with(x)").WithArguments("Create", "1").WithLocation(8, 6), // (11,6): error CS9405: No overload for method 'Create' takes 1 'with(...)' element arguments // c = [with(ref x)]; Diagnostic(ErrorCode.ERR_BadCollectionArgumentsArgCount, "with(ref x)").WithArguments("Create", "1").WithLocation(11, 6), // (14,6): error CS9405: No overload for method 'Create' takes 1 'with(...)' element arguments // c = [with(in x)]; Diagnostic(ErrorCode.ERR_BadCollectionArgumentsArgCount, "with(in x)").WithArguments("Create", "1").WithLocation(14, 6), // (17,6): error CS9405: No overload for method 'Create' takes 1 'with(...)' element arguments // c = [with(in r)]; Diagnostic(ErrorCode.ERR_BadCollectionArgumentsArgCount, "with(in r)").WithArguments("Create", "1").WithLocation(17, 6), // (20,6): error CS9405: No overload for method 'Create' takes 1 'with(...)' element arguments // c = [with(in ro)]; Diagnostic(ErrorCode.ERR_BadCollectionArgumentsArgCount, "with(in ro)").WithArguments("Create", "1").WithLocation(20, 6)); string sourceB2 = """ #pragma warning disable 219 // variable assigned but never used MyCollection<int> c; int x = 1; ref readonly int ro = ref x; c = [with(ref ro)]; """; comp = CreateCompilation([sourceA, sourceB2], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (5,15): error CS1510: A ref or out value must be an assignable variable // c = [with(ref ro)]; Diagnostic(ErrorCode.ERR_RefLvalueExpected, "ro").WithLocation(5, 15)); } [Fact] public void CollectionBuilder_InParameter_A() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] struct MyCollection<T> : IEnumerable<T> { private readonly List<T> _list; internal MyCollection(ReadOnlySpan<T> items, T arg) { _list = new(items.ToArray()); _list.Add(arg); } IEnumerator<T> IEnumerable<T>.GetEnumerator() => _list.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => _list.GetEnumerator(); } class MyBuilder { public static MyCollection<T> Create<T>(ReadOnlySpan<T> items) => throw null; public static MyCollection<T> Create<T>(in T x, ReadOnlySpan<T> items) => new(items, x); } """; string sourceB1 = """ #pragma warning disable 219 // variable assigned but never used MyCollection<int> c; int x = 1; ref int r = ref x; ref readonly int ro = ref x; c = [with(0)]; c.Report(); c = [with(x)]; c.Report(); x = 2; c = [with(ref x)]; c.Report(); x = 3; c = [with(in x)]; c.Report(); x = 4; c = [with(in r)]; c.Report(); x = 5; c = [with(in ro)]; c.Report(); """; CompileAndVerify( [sourceA, sourceB1, s_collectionExtensions], targetFramework: TargetFramework.Net80, expectedOutput: IncludeExpectedOutput("[0], [1], [2], [3], [4], [5], "), verify: Verification.FailsPEVerify).VerifyDiagnostics( // (11,15): warning CS9191: The 'ref' modifier for argument 1 corresponding to 'in' parameter is equivalent to 'in'. Consider using 'in' instead. // c = [with(ref x)]; Diagnostic(ErrorCode.WRN_BadArgRef, "x").WithArguments("1").WithLocation(11, 15)); string sourceB2 = """ #pragma warning disable 219 // variable assigned but never used MyCollection<int> c; int x = 1; ref readonly int ro = ref x; c = [with(ref ro)]; """; var comp = CreateCompilation([sourceA, sourceB2], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (5,15): error CS1510: A ref or out value must be an assignable variable // c = [with(ref ro)]; Diagnostic(ErrorCode.ERR_RefLvalueExpected, "ro").WithLocation(5, 15)); } [Fact] public void CollectionBuilder_OutParameter() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] struct MyCollection<T> : IEnumerable<T> { private readonly List<T> _list; internal MyCollection(ReadOnlySpan<T> items, T arg) { _list = new(items.ToArray()); _list.Add(arg); } IEnumerator<T> IEnumerable<T>.GetEnumerator() => _list.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => _list.GetEnumerator(); } class MyBuilder { public static MyCollection<T> Create<T>(ReadOnlySpan<T> items) => throw null; public static MyCollection<T> Create<T>(ReadOnlySpan<T> items, out T x) { x = default; return new(items, x); } } """; string sourceB1 = """ #pragma warning disable 219 // variable assigned but never used MyCollection<int> c; int x = 1; ref int r = ref x; c = [with(out x)]; c.Report(); x = 2; c = [with(out r), 3]; c.Report(); """; var comp = CreateCompilation( [sourceA, sourceB1, s_collectionExtensions], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (5,6): error CS9405: No overload for method 'Create' takes 1 'with(...)' element arguments // c = [with(out x)]; Diagnostic(ErrorCode.ERR_BadCollectionArgumentsArgCount, "with(out x)").WithArguments("Create", "1").WithLocation(5, 6), // (8,6): error CS9405: No overload for method 'Create' takes 1 'with(...)' element arguments // c = [with(out r), 3]; Diagnostic(ErrorCode.ERR_BadCollectionArgumentsArgCount, "with(out r)").WithArguments("Create", "1").WithLocation(8, 6)); string sourceB2 = """ #pragma warning disable 219 // variable assigned but never used MyCollection<int> c; int x = 1; c = [with(1)]; c = [with(x)]; c = [with(ref x)]; c = [with(in x)]; """; comp = CreateCompilation([sourceA, sourceB2], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (4,6): error CS9405: No overload for method 'Create' takes 1 'with(...)' element arguments // c = [with(1)]; Diagnostic(ErrorCode.ERR_BadCollectionArgumentsArgCount, "with(1)").WithArguments("Create", "1").WithLocation(4, 6), // (5,6): error CS9405: No overload for method 'Create' takes 1 'with(...)' element arguments // c = [with(x)]; Diagnostic(ErrorCode.ERR_BadCollectionArgumentsArgCount, "with(x)").WithArguments("Create", "1").WithLocation(5, 6), // (6,6): error CS9405: No overload for method 'Create' takes 1 'with(...)' element arguments // c = [with(ref x)]; Diagnostic(ErrorCode.ERR_BadCollectionArgumentsArgCount, "with(ref x)").WithArguments("Create", "1").WithLocation(6, 6), // (7,6): error CS9405: No overload for method 'Create' takes 1 'with(...)' element arguments // c = [with(in x)]; Diagnostic(ErrorCode.ERR_BadCollectionArgumentsArgCount, "with(in x)").WithArguments("Create", "1").WithLocation(7, 6)); } [Fact] public void CollectionBuilder_OutParameter_A() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] struct MyCollection<T> : IEnumerable<T> { private readonly List<T> _list; internal MyCollection(ReadOnlySpan<T> items, T arg) { _list = new(items.ToArray()); _list.Add(arg); } IEnumerator<T> IEnumerable<T>.GetEnumerator() => _list.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => _list.GetEnumerator(); } class MyBuilder { public static MyCollection<T> Create<T>(ReadOnlySpan<T> items) => throw null; public static MyCollection<T> Create<T>(out T x, ReadOnlySpan<T> items) { x = default; return new(items, x); } } """; string sourceB1 = """ #pragma warning disable 219 // variable assigned but never used MyCollection<int> c; int x = 1; ref int r = ref x; c = [with(out x)]; c.Report(); x = 2; c = [with(out r), 3]; c.Report(); """; var verifier = CompileAndVerify( [sourceA, sourceB1, s_collectionExtensions], targetFramework: TargetFramework.Net80, expectedOutput: IncludeExpectedOutput("[0], [3, 0], "), verify: Verification.FailsPEVerify); verifier.VerifyDiagnostics(); string sourceB2 = """ #pragma warning disable 219 // variable assigned but never used MyCollection<int> c; int x = 1; c = [with(1)]; c = [with(x)]; c = [with(ref x)]; c = [with(in x)]; """; var comp = CreateCompilation([sourceA, sourceB2], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (4,11): error CS1620: Argument 1 must be passed with the 'out' keyword // c = [with(1)]; Diagnostic(ErrorCode.ERR_BadArgRef, "1").WithArguments("1", "out").WithLocation(4, 11), // (5,11): error CS1620: Argument 1 must be passed with the 'out' keyword // c = [with(x)]; Diagnostic(ErrorCode.ERR_BadArgRef, "x").WithArguments("1", "out").WithLocation(5, 11), // (6,15): error CS1620: Argument 1 must be passed with the 'out' keyword // c = [with(ref x)]; Diagnostic(ErrorCode.ERR_BadArgRef, "x").WithArguments("1", "out").WithLocation(6, 15), // (7,14): error CS1620: Argument 1 must be passed with the 'out' keyword // c = [with(in x)]; Diagnostic(ErrorCode.ERR_BadArgRef, "x").WithArguments("1", "out").WithLocation(7, 14)); } [Fact] public void CollectionBuilder_RefParameter_Overloads() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] struct MyCollection<T> : IEnumerable<T> { private readonly List<T> _list; internal MyCollection(ReadOnlySpan<T> items, T x, T y) { _list = new(); _list.Add(x); _list.Add(y); _list.AddRange(items.ToArray()); } IEnumerator<T> IEnumerable<T>.GetEnumerator() => _list.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => _list.GetEnumerator(); } class MyBuilder { public static MyCollection<T> Create<T>(ReadOnlySpan<T> items) => default; public static MyCollection<T> Create<T>(ReadOnlySpan<T> items, in T x) => new(items, x, default); public static MyCollection<T> Create<T>(ReadOnlySpan<T> items, T x, ref T y) => new(items, x, y); public static MyCollection<T> Create<T>(ReadOnlySpan<T> items, out T x, T y) { x = default; return new(items, x, y); } } """; string sourceB = """ #pragma warning disable 219 // variable assigned but never used MyCollection<int> c; int x = 1; int y = 2; c = [with(in x)]; c.Report(); c = [with(1), 3]; c.Report(); c = [with(x, ref y)]; c.Report(); c = [with(out x, y), 3]; c.Report(); """; var comp = CreateCompilation( [sourceA, sourceB, s_collectionExtensions], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (5,6): error CS9405: No overload for method 'Create' takes 1 'with(...)' element arguments // c = [with(in x)]; Diagnostic(ErrorCode.ERR_BadCollectionArgumentsArgCount, "with(in x)").WithArguments("Create", "1").WithLocation(5, 6), // (7,6): error CS9405: No overload for method 'Create' takes 1 'with(...)' element arguments // c = [with(1), 3]; Diagnostic(ErrorCode.ERR_BadCollectionArgumentsArgCount, "with(1)").WithArguments("Create", "1").WithLocation(7, 6), // (9,6): error CS9405: No overload for method 'Create' takes 2 'with(...)' element arguments // c = [with(x, ref y)]; Diagnostic(ErrorCode.ERR_BadCollectionArgumentsArgCount, "with(x, ref y)").WithArguments("Create", "2").WithLocation(9, 6), // (11,6): error CS9405: No overload for method 'Create' takes 2 'with(...)' element arguments // c = [with(out x, y), 3]; Diagnostic(ErrorCode.ERR_BadCollectionArgumentsArgCount, "with(out x, y)").WithArguments("Create", "2").WithLocation(11, 6)); } [Fact] public void CollectionBuilder_RefParameter_Overloads_A() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] struct MyCollection<T> : IEnumerable<T> { private readonly List<T> _list; internal MyCollection(ReadOnlySpan<T> items, T x, T y) { _list = new(); _list.Add(x); _list.Add(y); _list.AddRange(items.ToArray()); } IEnumerator<T> IEnumerable<T>.GetEnumerator() => _list.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => _list.GetEnumerator(); } class MyBuilder { public static MyCollection<T> Create<T>(ReadOnlySpan<T> items) => default; public static MyCollection<T> Create<T>(in T x, ReadOnlySpan<T> items) => new(items, x, default); public static MyCollection<T> Create<T>(T x, ref T y, ReadOnlySpan<T> items) => new(items, x, y); public static MyCollection<T> Create<T>(out T x, T y, ReadOnlySpan<T> items) { x = default; return new(items, x, y); } } """; string sourceB = """ #pragma warning disable 219 // variable assigned but never used MyCollection<int> c; int x = 1; int y = 2; c = [with(in x)]; c.Report(); c = [with(1), 3]; c.Report(); c = [with(x, ref y)]; c.Report(); c = [with(out x, y), 3]; c.Report(); """; var verifier = CompileAndVerify( [sourceA, sourceB, s_collectionExtensions], targetFramework: TargetFramework.Net80, expectedOutput: IncludeExpectedOutput("[1, 0], [1, 0, 3], [1, 2], [0, 2, 3], "), verify: Verification.FailsPEVerify); verifier.VerifyDiagnostics(); } [Fact] public void CollectionBuilder_ReferenceImplicitParameter() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] struct MyCollection<T> : IEnumerable<T> { private readonly List<T> _list; internal MyCollection(ReadOnlySpan<T> items, T arg) { _list = new(items.ToArray()); _list.Add(arg); } IEnumerator<T> IEnumerable<T>.GetEnumerator() => _list.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => _list.GetEnumerator(); } class MyBuilder { public static MyCollection<T> Create<T>(ReadOnlySpan<T> items, T arg = default) => new(items, arg); } """; string sourceB = """ MyCollection<int> c; c = [with(items: default)]; c = [with(items: default, 1)]; c = [with(items: default, arg: 2)]; c = [with(3, items: default)]; c = [with(arg: 4, items: default)]; c = [with(default, 5)]; c = [with(default, arg: 6)]; """; var comp = CreateCompilation([sourceA, sourceB], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (2,5): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // c = [with(items: default)]; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[with(items: default)]").WithArguments("Create", "T", "MyCollection<T>").WithLocation(2, 5), // (2,18): error CS8716: There is no target type for the default literal. // c = [with(items: default)]; Diagnostic(ErrorCode.ERR_DefaultLiteralNoTargetType, "default").WithLocation(2, 18), // (3,5): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // c = [with(items: default, 1)]; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[with(items: default, 1)]").WithArguments("Create", "T", "MyCollection<T>").WithLocation(3, 5), // (3,18): error CS8716: There is no target type for the default literal. // c = [with(items: default, 1)]; Diagnostic(ErrorCode.ERR_DefaultLiteralNoTargetType, "default").WithLocation(3, 18), // (4,5): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // c = [with(items: default, arg: 2)]; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[with(items: default, arg: 2)]").WithArguments("Create", "T", "MyCollection<T>").WithLocation(4, 5), // (4,18): error CS8716: There is no target type for the default literal. // c = [with(items: default, arg: 2)]; Diagnostic(ErrorCode.ERR_DefaultLiteralNoTargetType, "default").WithLocation(4, 18), // (5,5): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // c = [with(3, items: default)]; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[with(3, items: default)]").WithArguments("Create", "T", "MyCollection<T>").WithLocation(5, 5), // (5,21): error CS8716: There is no target type for the default literal. // c = [with(3, items: default)]; Diagnostic(ErrorCode.ERR_DefaultLiteralNoTargetType, "default").WithLocation(5, 21), // (6,5): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // c = [with(arg: 4, items: default)]; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[with(arg: 4, items: default)]").WithArguments("Create", "T", "MyCollection<T>").WithLocation(6, 5), // (6,26): error CS8716: There is no target type for the default literal. // c = [with(arg: 4, items: default)]; Diagnostic(ErrorCode.ERR_DefaultLiteralNoTargetType, "default").WithLocation(6, 26), // (7,5): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // c = [with(default, 5)]; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[with(default, 5)]").WithArguments("Create", "T", "MyCollection<T>").WithLocation(7, 5), // (7,11): error CS8716: There is no target type for the default literal. // c = [with(default, 5)]; Diagnostic(ErrorCode.ERR_DefaultLiteralNoTargetType, "default").WithLocation(7, 11), // (8,5): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // c = [with(default, arg: 6)]; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[with(default, arg: 6)]").WithArguments("Create", "T", "MyCollection<T>").WithLocation(8, 5), // (8,11): error CS8716: There is no target type for the default literal. // c = [with(default, arg: 6)]; Diagnostic(ErrorCode.ERR_DefaultLiteralNoTargetType, "default").WithLocation(8, 11)); } [Fact] public void CollectionBuilder_ReferenceImplicitParameter_A() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] struct MyCollection<T> : IEnumerable<T> { private readonly List<T> _list; internal MyCollection(ReadOnlySpan<T> items, T arg) { _list = new(items.ToArray()); _list.Add(arg); } IEnumerator<T> IEnumerable<T>.GetEnumerator() => _list.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => _list.GetEnumerator(); } class MyBuilder { public static MyCollection<T> Create<T>(T arg = default, ReadOnlySpan<T> items = default) => new(items, arg); } """; string sourceB = """ MyCollection<int> c; c = [with(items: default)]; c = [with(items: default, 1)]; c = [with(items: default, arg: 2)]; c = [with(3, items: default)]; c = [with(arg: 4, items: default)]; c = [with(default, 5)]; c = [with(default, arg: 6)]; """; var comp = CreateCompilation([sourceA, sourceB], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (2,11): error CS1739: The best overload for 'Create' does not have a parameter named 'items' // c = [with(items: default)]; Diagnostic(ErrorCode.ERR_BadNamedArgument, "items").WithArguments("Create", "items").WithLocation(2, 11), // (3,11): error CS1739: The best overload for 'Create' does not have a parameter named 'items' // c = [with(items: default, 1)]; Diagnostic(ErrorCode.ERR_BadNamedArgument, "items").WithArguments("Create", "items").WithLocation(3, 11), // (4,11): error CS1739: The best overload for 'Create' does not have a parameter named 'items' // c = [with(items: default, arg: 2)]; Diagnostic(ErrorCode.ERR_BadNamedArgument, "items").WithArguments("Create", "items").WithLocation(4, 11), // (5,14): error CS1739: The best overload for 'Create' does not have a parameter named 'items' // c = [with(3, items: default)]; Diagnostic(ErrorCode.ERR_BadNamedArgument, "items").WithArguments("Create", "items").WithLocation(5, 14), // (6,19): error CS1739: The best overload for 'Create' does not have a parameter named 'items' // c = [with(arg: 4, items: default)]; Diagnostic(ErrorCode.ERR_BadNamedArgument, "items").WithArguments("Create", "items").WithLocation(6, 19), // (7,6): error CS9405: No overload for method 'Create' takes 2 'with(...)' element arguments // c = [with(default, 5)]; Diagnostic(ErrorCode.ERR_BadCollectionArgumentsArgCount, "with(default, 5)").WithArguments("Create", "2").WithLocation(7, 6), // (8,20): error CS1744: Named argument 'arg' specifies a parameter for which a positional argument has already been given // c = [with(default, arg: 6)]; Diagnostic(ErrorCode.ERR_NamedArgumentUsedInPositional, "arg").WithArguments("arg").WithLocation(8, 20)); } [Fact] public void CollectionBuilder_ReadOnlySpanConstraint() { string sourceA = """ namespace System { public ref struct ReadOnlySpan<T> where T : struct { } } """; string sourceB = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyCollection<T> : IEnumerable<T> { IEnumerator<T> IEnumerable<T>.GetEnumerator() => null; IEnumerator IEnumerable.GetEnumerator() => null; } class MyBuilder { public static MyCollection<T> Create<T>(ReadOnlySpan<T> items) => default; public static MyCollection<T> Create<T>(ReadOnlySpan<T> items, int arg) where T : struct => default; } """; string sourceC = """ class Program { static MyCollection<T> NoArgs<T>() => []; static MyCollection<T> EmptyArgs<T>() => [with()]; static MyCollection<T> WithArg<T>(int arg) => [with(arg)]; static MyCollection<T> Params<T>(params MyCollection<T> c) => c; } """; var comp = CreateCompilation([sourceA, sourceB, sourceC, CollectionBuilderAttributeDefinition]); comp.VerifyEmitDiagnostics( // (5,52): error CS9405: No overload for method 'Create' takes 1 'with(...)' element arguments // static MyCollection<T> WithArg<T>(int arg) => [with(arg)]; Diagnostic(ErrorCode.ERR_BadCollectionArgumentsArgCount, "with(arg)").WithArguments("Create", "1").WithLocation(5, 52), // (13,61): error CS0453: The type 'T' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'ReadOnlySpan<T>' // public static MyCollection<T> Create<T>(ReadOnlySpan<T> items) => default; Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "items").WithArguments("System.ReadOnlySpan<T>", "T", "T").WithLocation(13, 61)); } [Fact] public void CollectionBuilder_ReadOnlySpanConstraint_A() { string sourceA = """ namespace System { public ref struct ReadOnlySpan<T> where T : struct { } } """; string sourceB = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyCollection<T> : IEnumerable<T> { IEnumerator<T> IEnumerable<T>.GetEnumerator() => null; IEnumerator IEnumerable.GetEnumerator() => null; } class MyBuilder { public static MyCollection<T> Create<T>(ReadOnlySpan<T> items) => default; public static MyCollection<T> Create<T>(int arg, ReadOnlySpan<T> items) where T : struct => default; } """; string sourceC = """ class Program { static MyCollection<T> NoArgs<T>() => []; static MyCollection<T> EmptyArgs<T>() => [with()]; static MyCollection<T> WithArg<T>(int arg) => [with(arg)]; static MyCollection<T> Params<T>(params MyCollection<T> c) => c; } """; var comp = CreateCompilation([sourceA, sourceB, sourceC, CollectionBuilderAttributeDefinition]); comp.VerifyEmitDiagnostics( // (5,52): error CS0453: The type 'T' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'MyBuilder.Create<T>(int, ReadOnlySpan<T>)' // static MyCollection<T> WithArg<T>(int arg) => [with(arg)]; Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "with(arg)").WithArguments("MyBuilder.Create<T>(int, System.ReadOnlySpan<T>)", "T", "T").WithLocation(5, 52), // (13,61): error CS0453: The type 'T' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'ReadOnlySpan<T>' // public static MyCollection<T> Create<T>(ReadOnlySpan<T> items) => default; Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "items").WithArguments("System.ReadOnlySpan<T>", "T", "T").WithLocation(13, 61)); } [Fact] public void CollectionBuilder_SpreadElement_BoxingConversion() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyCollectionBuilder), nameof(MyCollectionBuilder.Create))] interface IMyCollection<T> : IEnumerable<T> { } class MyCollectionBuilder { public struct MyCollection<T> : IMyCollection<T> { private readonly List<T> _list; public MyCollection(ReadOnlySpan<T> items, T arg) { _list = new(items.ToArray()); _list.Add(arg); } public IEnumerator<T> GetEnumerator() => _list.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } public static MyCollection<T> Create<T>(ReadOnlySpan<T> items) => throw null; public static MyCollection<T> Create<T>(ReadOnlySpan<T> items, T arg) => new(items, arg); } """; string sourceB = """ #nullable enable using System; class Program { static void Main() { IMyCollection<string?> x = F<string>([], default!); x.Report(); IMyCollection<int> y = F<int>([1, 2], 3); y.Report(); } static IMyCollection<T?> F<T>(ReadOnlySpan<T> items, T arg) => [with(arg), ..items]; } """; var comp = CreateCompilation( [sourceA, sourceB, s_collectionExtensions], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (12,69): error CS9405: No overload for method 'Create' takes 1 'with(...)' element arguments // static IMyCollection<T?> F<T>(ReadOnlySpan<T> items, T arg) => [with(arg), ..items]; Diagnostic(ErrorCode.ERR_BadCollectionArgumentsArgCount, "with(arg)").WithArguments("Create", "1").WithLocation(12, 69)); } [Fact] public void CollectionBuilder_SpreadElement_BoxingConversion_A() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyCollectionBuilder), nameof(MyCollectionBuilder.Create))] interface IMyCollection<T> : IEnumerable<T> { } class MyCollectionBuilder { public struct MyCollection<T> : IMyCollection<T> { private readonly List<T> _list; public MyCollection(ReadOnlySpan<T> items, T arg) { _list = new(items.ToArray()); _list.Add(arg); } public IEnumerator<T> GetEnumerator() => _list.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } public static MyCollection<T> Create<T>(ReadOnlySpan<T> items) => throw null; public static MyCollection<T> Create<T>(T arg, ReadOnlySpan<T> items) => new(items, arg); } """; string sourceB = """ #nullable enable using System; class Program { static void Main() { IMyCollection<string?> x = F<string>([], default!); x.Report(); IMyCollection<int> y = F<int>([1, 2], 3); y.Report(); } static IMyCollection<T?> F<T>(ReadOnlySpan<T> items, T arg) => [with(arg), ..items]; } """; var verifier = CompileAndVerify( [sourceA, sourceB, s_collectionExtensions], targetFramework: TargetFramework.Net80, expectedOutput: IncludeExpectedOutput("[null], [1, 2, 3], "), verify: Verification.FailsPEVerify); verifier.VerifyDiagnostics(); } [Fact] public void CollectionBuilder_UseSiteError_Method() { // [CollectionBuilder(typeof(MyCollectionBuilder), "Create")] // public sealed class MyCollection<T> // { // public IEnumerator<T> GetEnumerator() { } // } // public static class MyCollectionBuilder // { // [CompilerFeatureRequired("MyFeature")] // public static MyCollection<T> MyCollectionBuilder.Create<T>(ReadOnlySpan<T>, object arg = null) { } // } string sourceA = """ .assembly extern System.Runtime { .ver 8:0:0:0 .publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A) } .class public sealed MyCollection`1<T> { .custom instance void [System.Runtime]System.Runtime.CompilerServices.CollectionBuilderAttribute::.ctor(class [System.Runtime]System.Type, string) = { type(MyCollectionBuilder) string('Create') } .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { ret } .method public instance class [System.Runtime]System.Collections.Generic.IEnumerator`1<!T> GetEnumerator() { ldnull ret } } .class public abstract sealed MyCollectionBuilder { .method public static class MyCollection`1<!!T> Create<T>(valuetype [System.Runtime]System.ReadOnlySpan`1<!!T> items, [opt] object arg) { .custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute::.ctor(string) = { string('MyFeature') } .param [2] = nullref ldnull ret } } """; var refA = CompileIL(sourceA); string sourceB = """ class Program { static void Main() { MyCollection<int> c; c = []; c = [with()]; c = [with(default)]; c = F(1, 2); } static MyCollection<T> F<T>(params MyCollection<T> c) => c; } """; var comp = CreateCompilation(sourceB, references: new[] { refA }, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (6,13): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // c = []; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[]").WithArguments("Create", "T", "MyCollection<T>").WithLocation(6, 13), // (7,13): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // c = [with()]; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[with()]").WithArguments("Create", "T", "MyCollection<T>").WithLocation(7, 13), // (8,13): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // c = [with(default)]; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[with(default)]").WithArguments("Create", "T", "MyCollection<T>").WithLocation(8, 13), // (8,19): error CS8716: There is no target type for the default literal. // c = [with(default)]; Diagnostic(ErrorCode.ERR_DefaultLiteralNoTargetType, "default").WithLocation(8, 19), // (9,13): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // c = F(1, 2); Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "F(1, 2)").WithArguments("Create", "T", "MyCollection<T>").WithLocation(9, 13), // (11,33): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // static MyCollection<T> F<T>(params MyCollection<T> c) => c; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "params MyCollection<T> c").WithArguments("Create", "T", "MyCollection<T>").WithLocation(11, 33)); } [Fact] public void CollectionBuilder_ObsoleteBuilderMethod_01() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyCollection<T> : IEnumerable<T> { IEnumerator<T> IEnumerable<T>.GetEnumerator() => default; IEnumerator IEnumerable.GetEnumerator() => default; } class MyBuilder { public static MyCollection<T> Create<T>(ReadOnlySpan<T> items) => default; [Obsolete] public static MyCollection<T> Create<T>(ReadOnlySpan<T> items, T arg) => default; } """; string sourceB = """ class Program { static void Main() { MyCollection<int> c; c = []; c = [with()]; c = [with(default)]; c = F(1, 2); } static MyCollection<T> F<T>(params MyCollection<T> c) => c; } """; var comp = CreateCompilation([sourceA, sourceB], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (8,14): error CS9405: No overload for method 'Create' takes 1 'with(...)' element arguments // c = [with(default)]; Diagnostic(ErrorCode.ERR_BadCollectionArgumentsArgCount, "with(default)").WithArguments("Create", "1").WithLocation(8, 14)); } [Fact] public void CollectionBuilder_ObsoleteBuilderMethod_01_A() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyCollection<T> : IEnumerable<T> { IEnumerator<T> IEnumerable<T>.GetEnumerator() => default; IEnumerator IEnumerable.GetEnumerator() => default; } class MyBuilder { public static MyCollection<T> Create<T>(ReadOnlySpan<T> items) => default; [Obsolete] public static MyCollection<T> Create<T>(T arg, ReadOnlySpan<T> items) => default; } """; string sourceB = """ class Program { static void Main() { MyCollection<int> c; c = []; c = [with()]; c = [with(default)]; c = F(1, 2); } static MyCollection<T> F<T>(params MyCollection<T> c) => c; } """; var comp = CreateCompilation([sourceA, sourceB], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (8,14): warning CS0612: 'MyBuilder.Create<T>(T, ReadOnlySpan<T>)' is obsolete // c = [with(default)]; Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "with(default)").WithArguments("MyBuilder.Create<T>(T, System.ReadOnlySpan<T>)").WithLocation(8, 14)); } [Fact] public void CollectionBuilder_ObsoleteBuilderMethod_02() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyCollection<T> : IEnumerable<T> { IEnumerator<T> IEnumerable<T>.GetEnumerator() => default; IEnumerator IEnumerable.GetEnumerator() => default; } class MyBuilder { [Obsolete] public static MyCollection<T> Create<T>(ReadOnlySpan<T> items, T arg = default) => default; } """; string sourceB = """ class Program { static void Main() { MyCollection<int> c; c = []; c = [with()]; c = [with(default)]; c = F(1, 2); } static MyCollection<T> F<T>(params MyCollection<T> c) => c; } """; var comp = CreateCompilation([sourceA, sourceB], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (6,13): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // c = []; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[]").WithArguments("Create", "T", "MyCollection<T>").WithLocation(6, 13), // (7,13): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // c = [with()]; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[with()]").WithArguments("Create", "T", "MyCollection<T>").WithLocation(7, 13), // (8,13): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // c = [with(default)]; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[with(default)]").WithArguments("Create", "T", "MyCollection<T>").WithLocation(8, 13), // (8,19): error CS8716: There is no target type for the default literal. // c = [with(default)]; Diagnostic(ErrorCode.ERR_DefaultLiteralNoTargetType, "default").WithLocation(8, 19), // (9,13): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // c = F(1, 2); Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "F(1, 2)").WithArguments("Create", "T", "MyCollection<T>").WithLocation(9, 13), // (11,33): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // static MyCollection<T> F<T>(params MyCollection<T> c) => c; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "params MyCollection<T> c").WithArguments("Create", "T", "MyCollection<T>").WithLocation(11, 33)); } [Fact] public void CollectionBuilder_ObsoleteBuilderMethod_02_A() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyCollection<T> : IEnumerable<T> { IEnumerator<T> IEnumerable<T>.GetEnumerator() => default; IEnumerator IEnumerable.GetEnumerator() => default; } class MyBuilder { [Obsolete] public static MyCollection<T> Create<T>(T arg = default, ReadOnlySpan<T> items = default) => default; } """; string sourceB = """ class Program { static void Main() { MyCollection<int> c; c = []; c = [with()]; c = [with(default)]; c = F(1, 2); } static MyCollection<T> F<T>(params MyCollection<T> c) => c; } """; var comp = CreateCompilation([sourceA, sourceB], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (6,13): warning CS0612: 'MyBuilder.Create<T>(T, ReadOnlySpan<T>)' is obsolete // c = []; Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "[]").WithArguments("MyBuilder.Create<T>(T, System.ReadOnlySpan<T>)").WithLocation(6, 13), // (7,14): warning CS0612: 'MyBuilder.Create<T>(T, ReadOnlySpan<T>)' is obsolete // c = [with()]; Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "with()").WithArguments("MyBuilder.Create<T>(T, System.ReadOnlySpan<T>)").WithLocation(7, 14), // (8,14): warning CS0612: 'MyBuilder.Create<T>(T, ReadOnlySpan<T>)' is obsolete // c = [with(default)]; Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "with(default)").WithArguments("MyBuilder.Create<T>(T, System.ReadOnlySpan<T>)").WithLocation(8, 14), // (9,13): warning CS0612: 'MyBuilder.Create<T>(T, ReadOnlySpan<T>)' is obsolete // c = F(1, 2); Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "F(1, 2)").WithArguments("MyBuilder.Create<T>(T, System.ReadOnlySpan<T>)").WithLocation(9, 13), // (11,33): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // static MyCollection<T> F<T>(params MyCollection<T> c) => c; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "params MyCollection<T> c").WithArguments("Create", "T", "MyCollection<T>").WithLocation(11, 33)); } [Fact] public void CollectionBuilder_UnmanagedCallersOnly() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyCollection : IEnumerable<int> { IEnumerator<int> IEnumerable<int>.GetEnumerator() => default; IEnumerator IEnumerable.GetEnumerator() => default; } class MyBuilder { [UnmanagedCallersOnly] public static MyCollection Create(ReadOnlySpan<int> items, params object[] args) => default; } """; string sourceB = """ class Program { static void Main() { MyCollection c; c = []; c = [with()]; c = [with(0)]; c = F(1, 2); } static MyCollection F(params MyCollection c) => c; } """; var comp = CreateCompilation([sourceA, sourceB], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (6,13): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<int>' and return type 'MyCollection'. // c = []; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[]").WithArguments("Create", "int", "MyCollection").WithLocation(6, 13), // (7,13): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<int>' and return type 'MyCollection'. // c = [with()]; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[with()]").WithArguments("Create", "int", "MyCollection").WithLocation(7, 13), // (8,13): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<int>' and return type 'MyCollection'. // c = [with(0)]; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[with(0)]").WithArguments("Create", "int", "MyCollection").WithLocation(8, 13), // (9,13): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<int>' and return type 'MyCollection'. // c = F(1, 2); Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "F(1, 2)").WithArguments("Create", "int", "MyCollection").WithLocation(9, 13), // (11,27): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<int>' and return type 'MyCollection'. // static MyCollection F(params MyCollection c) => c; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "params MyCollection c").WithArguments("Create", "int", "MyCollection").WithLocation(11, 27), // (15,19): error CS8894: Cannot use 'MyCollection' as a return type on a method attributed with 'UnmanagedCallersOnly'. // public static MyCollection Create(ReadOnlySpan<int> items, params object[] args) => default; Diagnostic(ErrorCode.ERR_CannotUseManagedTypeInUnmanagedCallersOnly, "MyCollection").WithArguments("MyCollection", "return").WithLocation(15, 19), // (15,39): error CS8894: Cannot use 'ReadOnlySpan<int>' as a parameter type on a method attributed with 'UnmanagedCallersOnly'. // public static MyCollection Create(ReadOnlySpan<int> items, params object[] args) => default; Diagnostic(ErrorCode.ERR_CannotUseManagedTypeInUnmanagedCallersOnly, "ReadOnlySpan<int> items").WithArguments("System.ReadOnlySpan<int>", "parameter").WithLocation(15, 39), // (15,64): error CS8894: Cannot use 'object[]' as a parameter type on a method attributed with 'UnmanagedCallersOnly'. // public static MyCollection Create(ReadOnlySpan<int> items, params object[] args) => default; Diagnostic(ErrorCode.ERR_CannotUseManagedTypeInUnmanagedCallersOnly, "params object[] args").WithArguments("object[]", "parameter").WithLocation(15, 64)); } [Fact] public void CollectionBuilder_GenericConstraints_01() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyCollection<T> : IEnumerable<T> { private readonly List<T> _items; public MyCollection(T arg, ReadOnlySpan<T> items) { _items = new(); _items.Add(arg); _items.AddRange(items.ToArray()); } public IEnumerator<T> GetEnumerator() => _items.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } class MyBuilder { public static MyCollection<T> Create<T>(ReadOnlySpan<T> items) => new(default, items); public static MyCollection<T> Create<T>(ReadOnlySpan<T> items, T arg) where T : struct => new(arg, items); } """; string sourceB1 = """ class Program { static void Main() { MyCollection<object> x; x = [with(), 1]; x.Report(); MyCollection<int> y; y = [with(2), 3]; y.Report(); x = F((object)1); x.Report(); y = F(3); y.Report(); } static MyCollection<T> F<T>(params MyCollection<T> c) => c; } """; var comp = CreateCompilation( [sourceA, sourceB1, s_collectionExtensions], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (9,14): error CS9405: No overload for method 'Create' takes 1 'with(...)' element arguments // y = [with(2), 3]; Diagnostic(ErrorCode.ERR_BadCollectionArgumentsArgCount, "with(2)").WithArguments("Create", "1").WithLocation(9, 14)); string sourceB2 = """ class Program { static void Main() { MyCollection<object> x; x = [with(default)]; x = [with(2), 3]; } } """; comp = CreateCompilation( [sourceA, sourceB2], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (6,14): error CS9405: No overload for method 'Create' takes 1 'with(...)' element arguments // x = [with(default)]; Diagnostic(ErrorCode.ERR_BadCollectionArgumentsArgCount, "with(default)").WithArguments("Create", "1").WithLocation(6, 14), // (7,14): error CS9405: No overload for method 'Create' takes 1 'with(...)' element arguments // x = [with(2), 3]; Diagnostic(ErrorCode.ERR_BadCollectionArgumentsArgCount, "with(2)").WithArguments("Create", "1").WithLocation(7, 14)); } [Fact] public void CollectionBuilder_GenericConstraints_01_A() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyCollection<T> : IEnumerable<T> { private readonly List<T> _items; public MyCollection(T arg, ReadOnlySpan<T> items) { _items = new(); _items.Add(arg); _items.AddRange(items.ToArray()); } public IEnumerator<T> GetEnumerator() => _items.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } class MyBuilder { public static MyCollection<T> Create<T>(ReadOnlySpan<T> items) => new(default, items); public static MyCollection<T> Create<T>(T arg, ReadOnlySpan<T> items) where T : struct => new(arg, items); } """; string sourceB1 = """ class Program { static void Main() { MyCollection<object> x; x = [with(), 1]; x.Report(); MyCollection<int> y; y = [with(2), 3]; y.Report(); x = F((object)1); x.Report(); y = F(3); y.Report(); } static MyCollection<T> F<T>(params MyCollection<T> c) => c; } """; var verifier = CompileAndVerify( [sourceA, sourceB1, s_collectionExtensions], targetFramework: TargetFramework.Net80, expectedOutput: IncludeExpectedOutput("[null, 1], [2, 3], [null, 1], [0, 3], "), verify: Verification.FailsPEVerify); verifier.VerifyDiagnostics(); string sourceB2 = """ class Program { static void Main() { MyCollection<object> x; x = [with(default)]; x = [with(2), 3]; } } """; var comp = CreateCompilation( [sourceA, sourceB2], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (6,14): error CS0453: The type 'object' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'MyBuilder.Create<T>(T, ReadOnlySpan<T>)' // x = [with(default)]; Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "with(default)").WithArguments("MyBuilder.Create<T>(T, System.ReadOnlySpan<T>)", "T", "object").WithLocation(6, 14), // (7,14): error CS0453: The type 'object' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'MyBuilder.Create<T>(T, ReadOnlySpan<T>)' // x = [with(2), 3]; Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "with(2)").WithArguments("MyBuilder.Create<T>(T, System.ReadOnlySpan<T>)", "T", "object").WithLocation(7, 14)); } [Fact] public void CollectionBuilder_GenericConstraints_02() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyCollection<T> : IEnumerable<T> { private readonly List<T> _items; public MyCollection(T arg, ReadOnlySpan<T> items) { _items = new(); _items.Add(arg); _items.AddRange(items.ToArray()); } public IEnumerator<T> GetEnumerator() => _items.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } class MyBuilder { public static MyCollection<T> Create<T>(ReadOnlySpan<T> items, T arg = default) where T : struct => new(arg, items); } """; string sourceB1 = """ class Program { static void Main() { MyCollection<int> c; c = []; c.Report(); c = [with(), 1]; c.Report(); c = [with(2)]; c.Report(); F<int>(); F(3); F(4, 5); } static void F<T>(params MyCollection<T> c) where T : struct { c.Report(); } } """; var comp = CreateCompilation( [sourceA, sourceB1, s_collectionExtensions], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (6,13): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // c = []; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[]").WithArguments("Create", "T", "MyCollection<T>").WithLocation(6, 13), // (8,13): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // c = [with(), 1]; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[with(), 1]").WithArguments("Create", "T", "MyCollection<T>").WithLocation(8, 13), // (10,13): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // c = [with(2)]; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[with(2)]").WithArguments("Create", "T", "MyCollection<T>").WithLocation(10, 13), // (12,9): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // F<int>(); Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "F<int>()").WithArguments("Create", "T", "MyCollection<T>").WithLocation(12, 9), // (13,9): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // F(3); Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "F(3)").WithArguments("Create", "T", "MyCollection<T>").WithLocation(13, 9), // (14,9): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // F(4, 5); Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "F(4, 5)").WithArguments("Create", "T", "MyCollection<T>").WithLocation(14, 9), // (16,22): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // static void F<T>(params MyCollection<T> c) where T : struct Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "params MyCollection<T> c").WithArguments("Create", "T", "MyCollection<T>").WithLocation(16, 22)); string sourceB2 = """ class Program { static void Main() { MyCollection<object> c; c = []; c = [with(), 1]; c = [with(2)]; F<object>(); F((object)3); } static void F<T>(params MyCollection<T> c) { } } """; comp = CreateCompilation( [sourceA, sourceB2], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (6,13): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // c = []; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[]").WithArguments("Create", "T", "MyCollection<T>").WithLocation(6, 13), // (7,13): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // c = [with(), 1]; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[with(), 1]").WithArguments("Create", "T", "MyCollection<T>").WithLocation(7, 13), // (8,13): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // c = [with(2)]; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[with(2)]").WithArguments("Create", "T", "MyCollection<T>").WithLocation(8, 13), // (9,9): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // F<object>(); Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "F<object>()").WithArguments("Create", "T", "MyCollection<T>").WithLocation(9, 9), // (10,9): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // F((object)3); Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "F((object)3)").WithArguments("Create", "T", "MyCollection<T>").WithLocation(10, 9), // (12,22): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // static void F<T>(params MyCollection<T> c) Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "params MyCollection<T> c").WithArguments("Create", "T", "MyCollection<T>").WithLocation(12, 22)); } [Fact] public void CollectionBuilder_GenericConstraints_02_A() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyCollection<T> : IEnumerable<T> { private readonly List<T> _items; public MyCollection(T arg, ReadOnlySpan<T> items) { _items = new(); _items.Add(arg); _items.AddRange(items.ToArray()); } public IEnumerator<T> GetEnumerator() => _items.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } class MyBuilder { public static MyCollection<T> Create<T>(T arg = default, ReadOnlySpan<T> items = default) where T : struct => new(arg, items); } """; string sourceB1 = """ class Program { static void Main() { MyCollection<int> c; c = []; c.Report(); c = [with(), 1]; c.Report(); c = [with(2)]; c.Report(); F<int>(); F(3); F(4, 5); } static void F<T>(params MyCollection<T> c) where T : struct { c.Report(); } } """; var comp = CreateCompilation( [sourceA, sourceB1, s_collectionExtensions], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (16,22): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // static void F<T>(params MyCollection<T> c) where T : struct Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "params MyCollection<T> c").WithArguments("Create", "T", "MyCollection<T>").WithLocation(16, 22)); string sourceB2 = """ class Program { static void Main() { MyCollection<object> c; c = []; c = [with(), 1]; c = [with(2)]; F<object>(); F((object)3); } static void F<T>(params MyCollection<T> c) { } } """; comp = CreateCompilation( [sourceA, sourceB2], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (6,13): error CS0453: The type 'object' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'MyBuilder.Create<T>(T, ReadOnlySpan<T>)' // c = []; Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "[]").WithArguments("MyBuilder.Create<T>(T, System.ReadOnlySpan<T>)", "T", "object").WithLocation(6, 13), // (7,14): error CS0453: The type 'object' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'MyBuilder.Create<T>(T, ReadOnlySpan<T>)' // c = [with(), 1]; Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "with()").WithArguments("MyBuilder.Create<T>(T, System.ReadOnlySpan<T>)", "T", "object").WithLocation(7, 14), // (8,14): error CS0453: The type 'object' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'MyBuilder.Create<T>(T, ReadOnlySpan<T>)' // c = [with(2)]; Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "with(2)").WithArguments("MyBuilder.Create<T>(T, System.ReadOnlySpan<T>)", "T", "object").WithLocation(8, 14), // (9,9): error CS0453: The type 'object' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'MyBuilder.Create<T>(T, ReadOnlySpan<T>)' // F<object>(); Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "F<object>()").WithArguments("MyBuilder.Create<T>(T, System.ReadOnlySpan<T>)", "T", "object").WithLocation(9, 9), // (10,9): error CS0453: The type 'object' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'MyBuilder.Create<T>(T, ReadOnlySpan<T>)' // F((object)3); Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "F((object)3)").WithArguments("MyBuilder.Create<T>(T, System.ReadOnlySpan<T>)", "T", "object").WithLocation(10, 9), // (12,22): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // static void F<T>(params MyCollection<T> c) Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "params MyCollection<T> c").WithArguments("Create", "T", "MyCollection<T>").WithLocation(12, 22)); } [Fact] public void CollectionBuilder_GenericConstraints_03() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyCollection<T> : IEnumerable<T> { private readonly List<T> _items; public MyCollection(T[] args, ReadOnlySpan<T> items) { _items = new(); _items.AddRange(args); _items.AddRange(items.ToArray()); } public IEnumerator<T> GetEnumerator() => _items.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } class MyBuilder { public static MyCollection<T> Create<T>(ReadOnlySpan<T> items, params T[] args) where T : struct => new(args, items); } """; string sourceB1 = """ class Program { static void Main() { MyCollection<int> c; c = []; c.Report(); c = [with(), 1]; c.Report(); c = [with(2, 3)]; c.Report(); F<int>(); F(4, 5); } static void F<T>(params MyCollection<T> c) where T : struct { c.Report(); } } """; var comp = CreateCompilation( [sourceA, sourceB1, s_collectionExtensions], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (6,13): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // c = []; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[]").WithArguments("Create", "T", "MyCollection<T>").WithLocation(6, 13), // (8,13): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // c = [with(), 1]; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[with(), 1]").WithArguments("Create", "T", "MyCollection<T>").WithLocation(8, 13), // (10,13): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // c = [with(2, 3)]; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[with(2, 3)]").WithArguments("Create", "T", "MyCollection<T>").WithLocation(10, 13), // (12,9): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // F<int>(); Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "F<int>()").WithArguments("Create", "T", "MyCollection<T>").WithLocation(12, 9), // (13,9): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // F(4, 5); Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "F(4, 5)").WithArguments("Create", "T", "MyCollection<T>").WithLocation(13, 9), // (15,22): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // static void F<T>(params MyCollection<T> c) where T : struct Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "params MyCollection<T> c").WithArguments("Create", "T", "MyCollection<T>").WithLocation(15, 22)); string sourceB2 = """ class Program { static void Main() { MyCollection<object> c; c = []; c = [with(), 1]; c = [with(2, 3)]; F<object>(); F((object)4, 5); } static void F<T>(params MyCollection<T> c) { } } """; comp = CreateCompilation( [sourceA, sourceB2], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (6,13): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // c = []; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[]").WithArguments("Create", "T", "MyCollection<T>").WithLocation(6, 13), // (7,13): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // c = [with(), 1]; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[with(), 1]").WithArguments("Create", "T", "MyCollection<T>").WithLocation(7, 13), // (8,13): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // c = [with(2, 3)]; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[with(2, 3)]").WithArguments("Create", "T", "MyCollection<T>").WithLocation(8, 13), // (9,9): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // F<object>(); Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "F<object>()").WithArguments("Create", "T", "MyCollection<T>").WithLocation(9, 9), // (10,9): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // F((object)4, 5); Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "F((object)4, 5)").WithArguments("Create", "T", "MyCollection<T>").WithLocation(10, 9), // (12,22): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // static void F<T>(params MyCollection<T> c) Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "params MyCollection<T> c").WithArguments("Create", "T", "MyCollection<T>").WithLocation(12, 22)); } [Fact] public void List_NoElements() { string source = """ using System; using System.Collections.Generic; class Program { static void Main() { Report(ListNoArguments<int>()); Report(ListEmptyArguments<int>()); Report(ListWithCapacity<int>(16)); } static void Report<T>(List<T> list) { Console.WriteLine("Count:{0}, Capacity:{1}", list.Count, list.Capacity); } static List<T> ListNoArguments<T>() => []; static List<T> ListEmptyArguments<T>() => [with()]; static List<T> ListWithCapacity<T>(int capacity) => [with(capacity: capacity)]; } """; var verifier = CompileAndVerify( source, expectedOutput: """ Count:0, Capacity:0 Count:0, Capacity:0 Count:0, Capacity:16 """); verifier.VerifyDiagnostics(); string expectedILNoArguments = """ { // Code size 6 (0x6) .maxstack 1 IL_0000: newobj "System.Collections.Generic.List<T>..ctor()" IL_0005: ret } """; verifier.VerifyIL("Program.ListNoArguments<T>", expectedILNoArguments); verifier.VerifyIL("Program.ListEmptyArguments<T>", expectedILNoArguments); verifier.VerifyIL("Program.ListWithCapacity<T>", """ { // Code size 7 (0x7) .maxstack 1 IL_0000: ldarg.0 IL_0001: newobj "System.Collections.Generic.List<T>..ctor(int)" IL_0006: ret } """); } [Fact] public void List_SingleSpread() { string source = """ using System; using System.Collections.Generic; class Program { static void Main() { Report(ListNoArguments([1, 2])); Report(ListEmptyArguments([3, 4])); Report(ListWithCapacity([5, 6], 16)); } static void Report<T>(List<T> list) { list.Report(); Console.WriteLine("Capacity:{0}", list.Capacity); } static List<T> ListNoArguments<T>(IEnumerable<T> e) => [..e]; static List<T> ListEmptyArguments<T>(IEnumerable<T> e) => [with(), ..e]; static List<T> ListWithCapacity<T>(IEnumerable<T> e, int capacity) => [with(capacity: capacity), ..e]; } """; var verifier = CompileAndVerify( [source, s_collectionExtensions], expectedOutput: """ [1, 2], Capacity:2 [3, 4], Capacity:4 [5, 6], Capacity:16 """); verifier.VerifyDiagnostics(); string expectedILNoArguments = """ { // Code size 7 (0x7) .maxstack 1 IL_0000: ldarg.0 IL_0001: call "System.Collections.Generic.List<T> System.Linq.Enumerable.ToList<T>(System.Collections.Generic.IEnumerable<T>)" IL_0006: ret } """; verifier.VerifyIL("Program.ListNoArguments<T>", expectedILNoArguments); verifier.VerifyIL("Program.ListEmptyArguments<T>", """ { // Code size 13 (0xd) .maxstack 3 IL_0000: newobj "System.Collections.Generic.List<T>..ctor()" IL_0005: dup IL_0006: ldarg.0 IL_0007: callvirt "void System.Collections.Generic.List<T>.AddRange(System.Collections.Generic.IEnumerable<T>)" IL_000c: ret } """); verifier.VerifyIL("Program.ListWithCapacity<T>", """ { // Code size 14 (0xe) .maxstack 3 IL_0000: ldarg.1 IL_0001: newobj "System.Collections.Generic.List<T>..ctor(int)" IL_0006: dup IL_0007: ldarg.0 IL_0008: callvirt "void System.Collections.Generic.List<T>.AddRange(System.Collections.Generic.IEnumerable<T>)" IL_000d: ret } """); } [Fact] public void CollectionBuilder_SingleSpread() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyCollection<T> : IEnumerable<T> { private readonly List<T> _items; public MyCollection(T[] args, ReadOnlySpan<T> items) { _items = new(); _items.AddRange(items.ToArray()); _items.AddRange(args); } public IEnumerator<T> GetEnumerator() => _items.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } class MyBuilder { public static MyCollection<T> Create<T>(ReadOnlySpan<T> items, params T[] args) => new(args, items); } """; string sourceB = """ using System; class Program { static void Main() { NoArguments([1, 2]).Report(); EmptyArguments([3, 4]).Report(); WithArguments([5, 6], 7).Report(); } static MyCollection<T> NoArguments<T>(ReadOnlySpan<T> s) => [..s]; static MyCollection<T> EmptyArguments<T>(ReadOnlySpan<T> s) => [with(), ..s]; static MyCollection<T> WithArguments<T>(ReadOnlySpan<T> s, params T[] args) => [with(args), ..s]; } """; var comp = CreateCompilation( [sourceA, sourceB, s_collectionExtensions], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (10,65): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // static MyCollection<T> NoArguments<T>(ReadOnlySpan<T> s) => [..s]; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[..s]").WithArguments("Create", "T", "MyCollection<T>").WithLocation(10, 65), // (11,68): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // static MyCollection<T> EmptyArguments<T>(ReadOnlySpan<T> s) => [with(), ..s]; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[with(), ..s]").WithArguments("Create", "T", "MyCollection<T>").WithLocation(11, 68), // (12,84): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // static MyCollection<T> WithArguments<T>(ReadOnlySpan<T> s, params T[] args) => [with(args), ..s]; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[with(args), ..s]").WithArguments("Create", "T", "MyCollection<T>").WithLocation(12, 84)); } [Fact] public void ImmutableArray_NoElements() { string sourceA = """ #pragma warning disable 436 // type conflicts with imported type using System.Collections.Generic; using System.Runtime.CompilerServices; namespace System.Collections.Immutable { [CollectionBuilder(typeof(MyBuilder), "Create")] public struct ImmutableArray<T> : IEnumerable<T> { public static readonly ImmutableArray<T> Empty = new(default, new T[0]); private readonly List<T> _items; internal ImmutableArray(ReadOnlySpan<T> items, T[] args) { _items = new(); _items.AddRange(items.ToArray()); _items.AddRange(args); } public IEnumerator<T> GetEnumerator() => _items.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } public static class MyBuilder { public static ImmutableArray<T> Create<T>(ReadOnlySpan<T> items, params T[] args) => new(items, args); } } """; string sourceB = """ #pragma warning disable 436 // type conflicts with imported type using System.Collections.Immutable; class Program { static void Main() { ImmutableArrayNoArguments<int>().Report(); ImmutableArrayEmptyArguments<int>().Report(); ImmutableArrayWithArguments(5, 6).Report(); } static ImmutableArray<T> ImmutableArrayNoArguments<T>() => []; static ImmutableArray<T> ImmutableArrayEmptyArguments<T>() => [with()]; static ImmutableArray<T> ImmutableArrayWithArguments<T>(params T[] args) => [with(args)]; } """; var comp = CreateCompilation( [sourceA, sourceB, s_collectionExtensions], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (11,64): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'ImmutableArray<T>'. // static ImmutableArray<T> ImmutableArrayNoArguments<T>() => []; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[]").WithArguments("Create", "T", "System.Collections.Immutable.ImmutableArray<T>").WithLocation(11, 64), // (12,67): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'ImmutableArray<T>'. // static ImmutableArray<T> ImmutableArrayEmptyArguments<T>() => [with()]; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[with()]").WithArguments("Create", "T", "System.Collections.Immutable.ImmutableArray<T>").WithLocation(12, 67), // (13,81): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'ImmutableArray<T>'. // static ImmutableArray<T> ImmutableArrayWithArguments<T>(params T[] args) => [with(args)]; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[with(args)]").WithArguments("Create", "T", "System.Collections.Immutable.ImmutableArray<T>").WithLocation(13, 81)); } [Fact] public void ImmutableArray_SingleSpread() { string sourceA = """ #pragma warning disable 436 // type conflicts with imported type using System.Collections.Generic; using System.Runtime.CompilerServices; namespace System.Collections.Immutable { [CollectionBuilder(typeof(MyBuilder), "Create")] public struct ImmutableArray<T> : IEnumerable<T> { private readonly List<T> _items; internal ImmutableArray(ReadOnlySpan<T> items, T[] args) { _items = new(); _items.AddRange(items.ToArray()); _items.AddRange(args); } public IEnumerator<T> GetEnumerator() => _items.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } public static class MyBuilder { public static ImmutableArray<T> Create<T>(ReadOnlySpan<T> items, params T[] args) => new(items, args); } } """; string sourceB = """ #pragma warning disable 436 // type conflicts with imported type using System; using System.Collections.Immutable; class Program { static void Main() { ImmutableArrayNoArguments([1, 2]).Report(); ImmutableArrayEmptyArguments([3, 4]).Report(); ImmutableArrayWithArguments([5, 6], 7).Report(); } static ImmutableArray<T> ImmutableArrayNoArguments<T>(ReadOnlySpan<T> s) => [..s]; static ImmutableArray<T> ImmutableArrayEmptyArguments<T>(ReadOnlySpan<T> s) => [with(), ..s]; static ImmutableArray<T> ImmutableArrayWithArguments<T>(ReadOnlySpan<T> s, params T[] args) => [with(args), ..s]; } """; var comp = CreateCompilation( [sourceA, sourceB, s_collectionExtensions], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (12,81): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'ImmutableArray<T>'. // static ImmutableArray<T> ImmutableArrayNoArguments<T>(ReadOnlySpan<T> s) => [..s]; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[..s]").WithArguments("Create", "T", "System.Collections.Immutable.ImmutableArray<T>").WithLocation(12, 81), // (13,84): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'ImmutableArray<T>'. // static ImmutableArray<T> ImmutableArrayEmptyArguments<T>(ReadOnlySpan<T> s) => [with(), ..s]; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[with(), ..s]").WithArguments("Create", "T", "System.Collections.Immutable.ImmutableArray<T>").WithLocation(13, 84), // (14,100): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'ImmutableArray<T>'. // static ImmutableArray<T> ImmutableArrayWithArguments<T>(ReadOnlySpan<T> s, params T[] args) => [with(args), ..s]; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[with(args), ..s]").WithArguments("Create", "T", "System.Collections.Immutable.ImmutableArray<T>").WithLocation(14, 100)); } [Theory, CombinatorialData] public void RefSafety_ConstructorArguments(bool scopedInParameter, bool scopedOutArgument) { string sourceA = $$""" using System.Collections; using System.Collections.Generic; ref struct R<T> { public R(ref T t) { } } class MyCollection<T> : IEnumerable<T> { public MyCollection() { } public MyCollection({{(scopedInParameter ? "scoped" : "")}} R<T> a, out R<T> b) { b = default; } public void Add(T t) { } IEnumerator<T> IEnumerable<T>.GetEnumerator() => null; IEnumerator IEnumerable.GetEnumerator() => null; } """; string sourceB = $$""" class Program { static void F<T>(T x, T y) { MyCollection<T> c; T t = default; R<T> a = new(ref t); {{(scopedOutArgument ? "scoped" : "")}} R<T> b; c = new(a, out b); c = [with(a, out b), x, y]; } } """; var comp = CreateCompilation([sourceA, sourceB]); if (scopedInParameter || scopedOutArgument) { comp.VerifyEmitDiagnostics(); } else { comp.VerifyEmitDiagnostics( // (9,13): error CS8350: This combination of arguments to 'MyCollection<T>.MyCollection(R<T>, out R<T>)' is disallowed because it may expose variables referenced by parameter 'a' outside of their declaration scope // c = new(a, out b); Diagnostic(ErrorCode.ERR_CallArgMixing, "new(a, out b)").WithArguments("MyCollection<T>.MyCollection(R<T>, out R<T>)", "a").WithLocation(9, 13), // (9,17): error CS8352: Cannot use variable 'a' in this context because it may expose referenced variables outside of their declaration scope // c = new(a, out b); Diagnostic(ErrorCode.ERR_EscapeVariable, "a").WithArguments("a").WithLocation(9, 17), // (10,14): error CS8350: This combination of arguments to 'MyCollection<T>.MyCollection(R<T>, out R<T>)' is disallowed because it may expose variables referenced by parameter 'a' outside of their declaration scope // c = [with(a, out b), x, y]; Diagnostic(ErrorCode.ERR_CallArgMixing, "with(a, out b)").WithArguments("MyCollection<T>.MyCollection(R<T>, out R<T>)", "a").WithLocation(10, 14), // (10,19): error CS8352: Cannot use variable 'a' in this context because it may expose referenced variables outside of their declaration scope // c = [with(a, out b), x, y]; Diagnostic(ErrorCode.ERR_EscapeVariable, "a").WithArguments("a").WithLocation(10, 19)); } } [Theory] [CombinatorialData] public void RefSafety_CollectionBuilderArguments(bool scopedInParameter, bool scopedOutArgument) { string sourceA = $$""" using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyCollection<T> : IEnumerable<T> { IEnumerator<T> IEnumerable<T>.GetEnumerator() => null; IEnumerator IEnumerable.GetEnumerator() => null; } class MyBuilder { public static MyCollection<T> Create<T>({{(scopedInParameter ? "scoped" : "")}} ReadOnlySpan<T> items, out ReadOnlySpan<T> other) { other = default; return default; } } """; string sourceB = $$""" using System; class Program { static void F<T>(T x, T y) { MyCollection<T> c; {{(scopedOutArgument ? "scoped" : "")}} ReadOnlySpan<T> s; c = MyBuilder.Create([x, y], out s); c = [with(out s), x, y]; } } """; var comp = CreateCompilation([sourceA, sourceB], targetFramework: TargetFramework.Net80); if (scopedInParameter || scopedOutArgument) { comp.VerifyEmitDiagnostics( // (9,13): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // c = [with(out s), x, y]; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[with(out s), x, y]").WithArguments("Create", "T", "MyCollection<T>").WithLocation(9, 13)); } else { comp.VerifyEmitDiagnostics( // (8,13): error CS8350: This combination of arguments to 'MyBuilder.Create<T>(ReadOnlySpan<T>, out ReadOnlySpan<T>)' is disallowed because it may expose variables referenced by parameter 'items' outside of their declaration scope // c = MyBuilder.Create([x, y], out s); Diagnostic(ErrorCode.ERR_CallArgMixing, "MyBuilder.Create([x, y], out s)").WithArguments("MyBuilder.Create<T>(System.ReadOnlySpan<T>, out System.ReadOnlySpan<T>)", "items").WithLocation(8, 13), // (8,30): error CS9203: A collection expression of type 'ReadOnlySpan<T>' cannot be used in this context because it may be exposed outside of the current scope. // c = MyBuilder.Create([x, y], out s); Diagnostic(ErrorCode.ERR_CollectionExpressionEscape, "[x, y]").WithArguments("System.ReadOnlySpan<T>").WithLocation(8, 30), // (9,13): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // c = [with(out s), x, y]; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[with(out s), x, y]").WithArguments("Create", "T", "MyCollection<T>").WithLocation(9, 13)); } } [Fact] public void Empty_TypeParameter() { string sourceA = """ using System.Collections; using System.Collections.Generic; interface IAdd<T> : IEnumerable<T> { void Add(T t); } struct MyCollection<T> : IAdd<T> { private List<T> _list; void IAdd<T>.Add(T t) { GetList().Add(t); } IEnumerator<T> IEnumerable<T>.GetEnumerator() => GetList().GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetList().GetEnumerator(); private List<T> GetList() => _list ??= new(); } """; string sourceB1 = """ class Program { static void Main() { NoArgs<int, MyCollection<int>>().Report(); EmptyArgs<int, MyCollection<int>>().Report(); } static U NoArgs<T, U>() where U : IAdd<T>, new() { return []; } static U EmptyArgs<T, U>() where U : IAdd<T>, new() { return [with()]; } } """; var verifier = CompileAndVerify( [sourceA, sourceB1, s_collectionExtensions], verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("[], [], ")); verifier.VerifyDiagnostics(); string expectedIL = """ { // Code size 6 (0x6) .maxstack 1 IL_0000: call "U System.Activator.CreateInstance<U>()" IL_0005: ret } """; verifier.VerifyIL("Program.NoArgs<T, U>", expectedIL); verifier.VerifyIL("Program.EmptyArgs<T, U>", expectedIL); string sourceB2 = """ class Program { static void Main() { NoArgs<int, MyCollection<int>>().Report(); EmptyArgs<int, MyCollection<int>>().Report(); } static U NoArgs<T, U>() where U : struct, IAdd<T> { return []; } static U EmptyArgs<T, U>() where U : struct, IAdd<T> { return [with()]; } } """; verifier = CompileAndVerify( [sourceA, sourceB2, s_collectionExtensions], verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("[], [], ")); verifier.VerifyDiagnostics(); expectedIL = """ { // Code size 6 (0x6) .maxstack 1 IL_0000: call "U System.Activator.CreateInstance<U>()" IL_0005: ret } """; verifier.VerifyIL("Program.NoArgs<T, U>", expectedIL); verifier.VerifyIL("Program.EmptyArgs<T, U>", expectedIL); } [Fact] public void Arguments_TypeParameter() { string sourceA = """ using System.Collections; using System.Collections.Generic; interface IAdd<T> : IEnumerable<T> { void Add(T t); } """; string sourceB = """ class Program { static void NonEmptyArgsNew<T, U>(T t) where U : IAdd<T>, new() { U x; x = [with(t), t]; x = [t, with(t)]; } static void NonEmptyArgsStruct<T, U>(T t) where U : struct, IAdd<T> { U y; y = [with(t), t]; y = [t, with(t)]; } } """; var comp = CreateCompilation([sourceA, sourceB]); comp.VerifyEmitDiagnostics( // (7,14): error CS0417: 'U': cannot provide arguments when creating an instance of a variable type // x = [with(t), t]; Diagnostic(ErrorCode.ERR_NewTyvarWithArgs, "with(t)").WithArguments("U").WithLocation(7, 14), // (8,17): error CS9400: 'with(...)' element must be the first element // x = [t, with(t)]; Diagnostic(ErrorCode.ERR_CollectionArgumentsMustBeFirst, "with").WithLocation(8, 17), // (14,14): error CS0417: 'U': cannot provide arguments when creating an instance of a variable type // y = [with(t), t]; Diagnostic(ErrorCode.ERR_NewTyvarWithArgs, "with(t)").WithArguments("U").WithLocation(14, 14), // (15,17): error CS9400: 'with(...)' element must be the first element // y = [t, with(t)]; Diagnostic(ErrorCode.ERR_CollectionArgumentsMustBeFirst, "with").WithLocation(15, 17)); } [Fact] public void UnrecognizedType() { string source = """ class Program { static A EmptyArgs() => [with()]; static B NonEmptyArgs() => [with(default)]; } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (3,12): error CS0246: The type or namespace name 'A' could not be found (are you missing a using directive or an assembly reference?) // static A EmptyArgs() => [with()]; Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "A").WithArguments("A").WithLocation(3, 12), // (4,12): error CS0246: The type or namespace name 'B' could not be found (are you missing a using directive or an assembly reference?) // static B NonEmptyArgs() => [with(default)]; Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "B").WithArguments("B").WithLocation(4, 12)); } [Fact] public void EvaluationOrder_CollectionInitializer() { string sourceA = """ using System; class A { private int _i; private A(int i) { _i = i; } public static implicit operator A(int i) { Console.WriteLine("{0} -> A", i); return new(i); } public override string ToString() => _i.ToString(); } """; string sourceB = """ using System; using System.Collections; using System.Collections.Generic; class MyCollection<T> : IEnumerable<T> { public MyCollection(A x = null, A y = null) { Console.WriteLine("MyCollection({0}, {1})", x, y); } public void Add(T t) { Console.WriteLine("Add({0})", t); } IEnumerator<T> IEnumerable<T>.GetEnumerator() => throw null; IEnumerator IEnumerable.GetEnumerator() => throw null; } """; string sourceC = """ using System; class Program { static void Main() { MyCollection<A> c; c = [with(y: Identity(1), x: Identity(2)), Identity(3), Identity(4)]; } static T Identity<T>(T value) { Console.WriteLine(value); return value; } } """; var verifier = CompileAndVerify( [sourceA, sourceB, sourceC], expectedOutput: """ 1 1 -> A 2 2 -> A MyCollection(2, 1) 3 3 -> A Add(3) 4 4 -> A Add(4) """); verifier.VerifyDiagnostics(); verifier.VerifyIL("Program.Main()", """ { // Code size 65 (0x41) .maxstack 3 .locals init (A V_0) IL_0000: ldc.i4.1 IL_0001: call "int Program.Identity<int>(int)" IL_0006: call "A A.op_Implicit(int)" IL_000b: stloc.0 IL_000c: ldc.i4.2 IL_000d: call "int Program.Identity<int>(int)" IL_0012: call "A A.op_Implicit(int)" IL_0017: ldloc.0 IL_0018: newobj "MyCollection<A>..ctor(A, A)" IL_001d: dup IL_001e: ldc.i4.3 IL_001f: call "int Program.Identity<int>(int)" IL_0024: call "A A.op_Implicit(int)" IL_0029: callvirt "void MyCollection<A>.Add(A)" IL_002e: dup IL_002f: ldc.i4.4 IL_0030: call "int Program.Identity<int>(int)" IL_0035: call "A A.op_Implicit(int)" IL_003a: callvirt "void MyCollection<A>.Add(A)" IL_003f: pop IL_0040: ret } """); } [Fact] public void EvaluationOrder_CollectionBuilder() { string sourceA = """ using System; class A { private int _i; private A(int i) { _i = i; } public static implicit operator A(int i) { Console.WriteLine("{0} -> A", i); return new(i); } public override string ToString() => _i.ToString(); } """; string sourceB = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyCollection<T> : IEnumerable<T> { public MyCollection(ReadOnlySpan<T> items, A x, A y) { Console.WriteLine("MyCollection({0}, {1})", x, y); Console.WriteLine(items.Length); } IEnumerator<T> IEnumerable<T>.GetEnumerator() => throw null; IEnumerator IEnumerable.GetEnumerator() => throw null; } class MyBuilder { public static MyCollection<T> Create<T>(ReadOnlySpan<T> items, A x = null, A y = null) => new(items, x, y); } """; string sourceC = """ using System; class Program { static void Main() { MyCollection<A> c; c = [with(y: Identity(1), x: Identity(2)), Identity(3), Identity(4)]; } static T Identity<T>(T value) { Console.WriteLine(value); return value; } } """; var comp = CreateCompilation( [sourceA, sourceB, sourceC], targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (7,13): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method whose last parameter is of type 'ReadOnlySpan<T>' and return type 'MyCollection<T>'. // c = [with(y: Identity(1), x: Identity(2)), Identity(3), Identity(4)]; Diagnostic(ErrorCode.ERR_CollectionBuilderAttributeMethodNotFound, "[with(y: Identity(1), x: Identity(2)), Identity(3), Identity(4)]").WithArguments("Create", "T", "MyCollection<T>").WithLocation(7, 13)); } [Fact] public void EvaluationOrder_CollectionBuilder_A() { string sourceA = """ using System; class A { private int _i; private A(int i) { _i = i; } public static implicit operator A(int i) { Console.WriteLine("{0} -> A", i); return new(i); } public override string ToString() => _i.ToString(); } """; string sourceB = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyCollection<T> : IEnumerable<T> { public MyCollection(ReadOnlySpan<T> items, A x, A y) { Console.WriteLine("MyCollection({0}, {1})", x, y); Console.WriteLine(items.Length); } IEnumerator<T> IEnumerable<T>.GetEnumerator() => throw null; IEnumerator IEnumerable.GetEnumerator() => throw null; } class MyBuilder { public static MyCollection<T> Create<T>(A x = null, A y = null, ReadOnlySpan<T> items = default) => new(items, x, y); } """; string sourceC = """ using System; class Program { static void Main() { MyCollection<A> c; c = [with(y: Identity(1), x: Identity(2)), Identity(3), Identity(4)]; } static T Identity<T>(T value) { Console.WriteLine(value); return value; } } """; var comp = CompileAndVerify( [sourceA, sourceB, sourceC], targetFramework: TargetFramework.Net80, expectedOutput: IncludeExpectedOutput(""" 1 1 -> A 2 2 -> A 3 3 -> A 4 4 -> A MyCollection(2, 1) 2 """), verify: Verification.Fails).VerifyIL("Program.Main", """ { // Code size 87 (0x57) .maxstack 4 .locals init (<>y__InlineArray2<A> V_0, A V_1) IL_0000: ldc.i4.1 IL_0001: call "int Program.Identity<int>(int)" IL_0006: call "A A.op_Implicit(int)" IL_000b: stloc.1 IL_000c: ldc.i4.2 IL_000d: call "int Program.Identity<int>(int)" IL_0012: call "A A.op_Implicit(int)" IL_0017: ldloc.1 IL_0018: ldloca.s V_0 IL_001a: initobj "<>y__InlineArray2<A>" IL_0020: ldloca.s V_0 IL_0022: ldc.i4.0 IL_0023: call "ref A <PrivateImplementationDetails>.InlineArrayElementRef<<>y__InlineArray2<A>, A>(ref <>y__InlineArray2<A>, int)" IL_0028: ldc.i4.3 IL_0029: call "int Program.Identity<int>(int)" IL_002e: call "A A.op_Implicit(int)" IL_0033: stind.ref IL_0034: ldloca.s V_0 IL_0036: ldc.i4.1 IL_0037: call "ref A <PrivateImplementationDetails>.InlineArrayElementRef<<>y__InlineArray2<A>, A>(ref <>y__InlineArray2<A>, int)" IL_003c: ldc.i4.4 IL_003d: call "int Program.Identity<int>(int)" IL_0042: call "A A.op_Implicit(int)" IL_0047: stind.ref IL_0048: ldloca.s V_0 IL_004a: ldc.i4.2 IL_004b: call "System.ReadOnlySpan<A> <PrivateImplementationDetails>.InlineArrayAsReadOnlySpan<<>y__InlineArray2<A>, A>(in <>y__InlineArray2<A>, int)" IL_0050: call "MyCollection<A> MyBuilder.Create<A>(A, A, System.ReadOnlySpan<A>)" IL_0055: pop IL_0056: ret } """); } [Fact] public void EvaluationOrder_CollectionBuilder_B() { string sourceA = """ using System; class A { private int _i; private A(int i) { _i = i; } public static implicit operator A(int i) { Console.WriteLine("{0} -> A", i); return new(i); } public override string ToString() => _i.ToString(); } """; string sourceB = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyCollection<T> : IEnumerable<T> { public MyCollection(ReadOnlySpan<T> items, A x, A y) { Console.WriteLine("MyCollection({0}, {1})", x, y); Console.WriteLine(items.Length); } IEnumerator<T> IEnumerable<T>.GetEnumerator() => throw null; IEnumerator IEnumerable.GetEnumerator() => throw null; } class MyBuilder { public static MyCollection<T> Create<T>(A x = null, A y = null, ReadOnlySpan<T> items = default) => new(items, x, y); } """; string sourceC = """ using System; class Program { static void Main() { MyCollection<A> c; c = [with(y: Identity(1)), Identity(3), Identity(4)]; } static T Identity<T>(T value) { Console.WriteLine(value); return value; } } """; var comp = CompileAndVerify( [sourceA, sourceB, sourceC], targetFramework: TargetFramework.Net80, expectedOutput: IncludeExpectedOutput(""" 1 1 -> A 3 3 -> A 4 4 -> A MyCollection(, 1) 2 """), verify: Verification.Fails).VerifyIL("Program.Main", """ { // Code size 75 (0x4b) .maxstack 4 .locals init (<>y__InlineArray2<A> V_0) IL_0000: ldnull IL_0001: ldc.i4.1 IL_0002: call "int Program.Identity<int>(int)" IL_0007: call "A A.op_Implicit(int)" IL_000c: ldloca.s V_0 IL_000e: initobj "<>y__InlineArray2<A>" IL_0014: ldloca.s V_0 IL_0016: ldc.i4.0 IL_0017: call "ref A <PrivateImplementationDetails>.InlineArrayElementRef<<>y__InlineArray2<A>, A>(ref <>y__InlineArray2<A>, int)" IL_001c: ldc.i4.3 IL_001d: call "int Program.Identity<int>(int)" IL_0022: call "A A.op_Implicit(int)" IL_0027: stind.ref IL_0028: ldloca.s V_0 IL_002a: ldc.i4.1 IL_002b: call "ref A <PrivateImplementationDetails>.InlineArrayElementRef<<>y__InlineArray2<A>, A>(ref <>y__InlineArray2<A>, int)" IL_0030: ldc.i4.4 IL_0031: call "int Program.Identity<int>(int)" IL_0036: call "A A.op_Implicit(int)" IL_003b: stind.ref IL_003c: ldloca.s V_0 IL_003e: ldc.i4.2 IL_003f: call "System.ReadOnlySpan<A> <PrivateImplementationDetails>.InlineArrayAsReadOnlySpan<<>y__InlineArray2<A>, A>(in <>y__InlineArray2<A>, int)" IL_0044: call "MyCollection<A> MyBuilder.Create<A>(A, A, System.ReadOnlySpan<A>)" IL_0049: pop IL_004a: ret } """); } [Fact] public void EvaluationOrder_CollectionBuilder_C() { string sourceA = """ using System; class A { private int _i; private A(int i) { _i = i; } public static implicit operator A(int i) { Console.WriteLine("{0} -> A", i); return new(i); } public override string ToString() => _i.ToString(); } """; string sourceB = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyCollection<T> : IEnumerable<T> { public MyCollection(ReadOnlySpan<T> items, A x, A y) { Console.WriteLine("MyCollection({0}, {1})", x, y); Console.WriteLine(items.Length); } IEnumerator<T> IEnumerable<T>.GetEnumerator() => throw null; IEnumerator IEnumerable.GetEnumerator() => throw null; } class MyBuilder { public static MyCollection<T> Create<T>(A x = null, A y = null, ReadOnlySpan<T> items = default) => new(items, x, y); } """; string sourceC = """ using System; class Program { static void Main() { MyCollection<A> c; c = [with(), Identity(3), Identity(4)]; } static T Identity<T>(T value) { Console.WriteLine(value); return value; } } """; var comp = CompileAndVerify( [sourceA, sourceB, sourceC], targetFramework: TargetFramework.Net80, expectedOutput: IncludeExpectedOutput(""" 3 3 -> A 4 4 -> A MyCollection(, ) 2 """), verify: Verification.Fails).VerifyIL("Program.Main", """ { // Code size 65 (0x41) .maxstack 4 .locals init (<>y__InlineArray2<A> V_0) IL_0000: ldnull IL_0001: ldnull IL_0002: ldloca.s V_0 IL_0004: initobj "<>y__InlineArray2<A>" IL_000a: ldloca.s V_0 IL_000c: ldc.i4.0 IL_000d: call "ref A <PrivateImplementationDetails>.InlineArrayElementRef<<>y__InlineArray2<A>, A>(ref <>y__InlineArray2<A>, int)" IL_0012: ldc.i4.3 IL_0013: call "int Program.Identity<int>(int)" IL_0018: call "A A.op_Implicit(int)" IL_001d: stind.ref IL_001e: ldloca.s V_0 IL_0020: ldc.i4.1 IL_0021: call "ref A <PrivateImplementationDetails>.InlineArrayElementRef<<>y__InlineArray2<A>, A>(ref <>y__InlineArray2<A>, int)" IL_0026: ldc.i4.4 IL_0027: call "int Program.Identity<int>(int)" IL_002c: call "A A.op_Implicit(int)" IL_0031: stind.ref IL_0032: ldloca.s V_0 IL_0034: ldc.i4.2 IL_0035: call "System.ReadOnlySpan<A> <PrivateImplementationDetails>.InlineArrayAsReadOnlySpan<<>y__InlineArray2<A>, A>(in <>y__InlineArray2<A>, int)" IL_003a: call "MyCollection<A> MyBuilder.Create<A>(A, A, System.ReadOnlySpan<A>)" IL_003f: pop IL_0040: ret } """); } [Fact] public void Arglist() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; class MyCollection : IEnumerable { public readonly List<int> Args; public MyCollection() { Args = new(); } public MyCollection(__arglist) { Args = GetArgs(0, new ArgIterator(__arglist)); } public MyCollection(int x, __arglist) { Args = GetArgs(x, new ArgIterator(__arglist)); } private static List<int> GetArgs(int x, ArgIterator iterator) { var args = new List<int>(); args.Add(x); while (iterator.GetRemainingCount() > 0) args.Add(__refvalue(iterator.GetNextArg(), int)); return args; } public void Add(object o) { } IEnumerator IEnumerable.GetEnumerator() => throw null; } """; string sourceB = """ class Program { static void Main() { F1().Args.Report(); F2().Args.Report(); F3(1, 2).Args.Report(); F4(3, 4).Args.Report(); } static MyCollection F1() => [with()]; static MyCollection F2() => [with(__arglist())]; static MyCollection F3(int x, int y) => [with(__arglist(x, y))]; static MyCollection F4(int x, int y) => [with(x, __arglist(y))]; } """; var verifier = CompileAndVerify( [sourceA, sourceB, s_collectionExtensions], targetFramework: TargetFramework.NetFramework, verify: Verification.FailsILVerify, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? null : "[], [0], [0, 1, 2], [3, 4], "); verifier.VerifyDiagnostics(); verifier.VerifyIL("Program.F1", """ { // Code size 6 (0x6) .maxstack 1 IL_0000: newobj "MyCollection..ctor()" IL_0005: ret } """); verifier.VerifyIL("Program.F2", """ { // Code size 6 (0x6) .maxstack 1 IL_0000: newobj "MyCollection..ctor(__arglist)" IL_0005: ret } """); verifier.VerifyIL("Program.F3", """ { // Code size 8 (0x8) .maxstack 2 IL_0000: ldarg.0 IL_0001: ldarg.1 IL_0002: newobj "MyCollection..ctor(__arglist) with __arglist( int, int)" IL_0007: ret } """); verifier.VerifyIL("Program.F4", """ { // Code size 8 (0x8) .maxstack 2 IL_0000: ldarg.0 IL_0001: ldarg.1 IL_0002: newobj "MyCollection..ctor(int, __arglist) with __arglist( int)" IL_0007: ret } """); } [Fact] public void Arglist_NoParameterlessConstructor() { string sourceA = """ using System; using System.Collections; class MyCollection : IEnumerable { public MyCollection(__arglist) { } public void Add(object o) { } IEnumerator IEnumerable.GetEnumerator() => throw null; } """; string sourceB = """ using System; class Program { static void Main() { MyCollection c; c = []; c = [with()]; c = [with(__arglist())]; c = [with(__arglist(0))]; } } """; var comp = CreateCompilation([sourceA, sourceB]); comp.VerifyEmitDiagnostics( // (7,13): error CS9214: Collection expression type must have an applicable constructor that can be called with no arguments. // c = []; Diagnostic(ErrorCode.ERR_CollectionExpressionMissingConstructor, "[]").WithLocation(7, 13), // (8,14): error CS7036: There is no argument given that corresponds to the required parameter '__arglist' of 'MyCollection.MyCollection(__arglist)' // c = [with()]; Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "with()").WithArguments("__arglist", "MyCollection.MyCollection(__arglist)").WithLocation(8, 14)); } [Fact] public void DynamicArguments_01() { string source = """ using System.Collections.Generic; class Program { static void Main() { List<object> l; l = [with(), (dynamic)2]; l = [with(capacity: 1)]; l = [with(capacity: (dynamic)1)]; } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (9,29): error CS9503: Collection arguments cannot be dynamic; compile-time binding is required. // l = [with(capacity: (dynamic)1)]; Diagnostic(ErrorCode.ERR_CollectionArgumentsDynamicBinding, "(dynamic)1").WithLocation(9, 29)); } [Fact] public void DynamicArguments_02() { string sourceA = """ using System.Collections; using System.Collections.Generic; class MyCollection<T> : IEnumerable<T> { public MyCollection(object x = null, object y = null) { } public void Add(T t) { } IEnumerator<T> IEnumerable<T>.GetEnumerator() => throw null; IEnumerator IEnumerable.GetEnumerator() => throw null; } """; string sourceB = """ class Program { static void Main() { MyCollection<int> c; c = [with(), (dynamic)3]; c = [with(1)]; c = [with(y: "2")]; c = [with(1, "2"), (dynamic)3]; c = [with((dynamic)1)]; c = [with(y: (dynamic)"2")]; c = [3, with(1, (dynamic)"2")]; c = [with((dynamic)1, (dynamic)"2"), 3]; c = [with(x => { })]; } } """; var comp = CreateCompilation([sourceA, sourceB]); comp.VerifyEmitDiagnostics( // (10,19): error CS9503: Collection arguments cannot be dynamic; compile-time binding is required. // c = [with((dynamic)1)]; Diagnostic(ErrorCode.ERR_CollectionArgumentsDynamicBinding, "(dynamic)1").WithLocation(10, 19), // (11,22): error CS9503: Collection arguments cannot be dynamic; compile-time binding is required. // c = [with(y: (dynamic)"2")]; Diagnostic(ErrorCode.ERR_CollectionArgumentsDynamicBinding, @"(dynamic)""2""").WithLocation(11, 22), // (12,17): error CS9501: Collection argument element must be the first element. // c = [3, with(1, (dynamic)"2")]; Diagnostic(ErrorCode.ERR_CollectionArgumentsMustBeFirst, "with").WithLocation(12, 17), // (12,25): error CS9503: Collection arguments cannot be dynamic; compile-time binding is required. // c = [3, with(1, (dynamic)"2")]; Diagnostic(ErrorCode.ERR_CollectionArgumentsDynamicBinding, @"(dynamic)""2""").WithLocation(12, 25), // (13,19): error CS9503: Collection arguments cannot be dynamic; compile-time binding is required. // c = [with((dynamic)1, (dynamic)"2"), 3]; Diagnostic(ErrorCode.ERR_CollectionArgumentsDynamicBinding, "(dynamic)1").WithLocation(13, 19), // (13,31): error CS9503: Collection arguments cannot be dynamic; compile-time binding is required. // c = [with((dynamic)1, (dynamic)"2"), 3]; Diagnostic(ErrorCode.ERR_CollectionArgumentsDynamicBinding, @"(dynamic)""2""").WithLocation(13, 31), // (14,21): error CS8917: The delegate type could not be inferred. // c = [with(x => { })]; Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "=>").WithLocation(14, 21)); } [Theory] [InlineData("ref")] [InlineData("in ")] [InlineData("out")] public void DynamicArguments_03(string refKind) { string source = $$""" using System.Collections; using System.Collections.Generic; class MyCollection<T> : IEnumerable<T> { public MyCollection() { } public MyCollection({{refKind}} object obj) { throw null; } public void Add(T t) { } IEnumerator<T> IEnumerable<T>.GetEnumerator() => throw null; IEnumerator IEnumerable.GetEnumerator() => throw null; } class Program { static void Main() { object o = null; dynamic d = o; MyCollection<object> c; c = [with({{refKind}} o)]; c = [with({{refKind}} d)]; } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (19,23): error CS9503: Collection arguments cannot be dynamic; compile-time binding is required. // c = [with(in d)]; Diagnostic(ErrorCode.ERR_CollectionArgumentsDynamicBinding, "d").WithLocation(19, 23)); } [Fact] public void DynamicArguments_04() { string sourceA = """ using System.Collections; using System.Collections.Generic; class MyCollection : IEnumerable { public MyCollection(dynamic d = null) { } public void Add(object o) { } IEnumerator IEnumerable.GetEnumerator() => throw null; } """; string sourceB = """ class Program { static void Main() { object o = null; dynamic d = o; MyCollection c; c = [with()]; c = [with(null)]; c = [with(default)]; c = [with(0)]; c = [with((dynamic)null)]; c = [with((dynamic)0)]; c = [with(o)]; c = [with(d)]; } } """; var comp = CreateCompilation([sourceA, sourceB]); comp.VerifyEmitDiagnostics( // (12,19): error CS9503: Collection arguments cannot be dynamic; compile-time binding is required. // c = [with((dynamic)null)]; Diagnostic(ErrorCode.ERR_CollectionArgumentsDynamicBinding, "(dynamic)null").WithLocation(12, 19), // (13,19): error CS9503: Collection arguments cannot be dynamic; compile-time binding is required. // c = [with((dynamic)0)]; Diagnostic(ErrorCode.ERR_CollectionArgumentsDynamicBinding, "(dynamic)0").WithLocation(13, 19), // (15,19): error CS9503: Collection arguments cannot be dynamic; compile-time binding is required. // c = [with(d)]; Diagnostic(ErrorCode.ERR_CollectionArgumentsDynamicBinding, "d").WithLocation(15, 19)); } [Fact] public void DynamicArguments_05() { string source = """ class Program { static void Main() { A a; a = [with(null), (dynamic)null]; a = [with((dynamic)null), null]; } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (5,9): error CS0246: The type or namespace name 'A' could not be found (are you missing a using directive or an assembly reference?) // A a; Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "A").WithArguments("A").WithLocation(5, 9), // (7,19): error CS9503: Collection arguments cannot be dynamic; compile-time binding is required. // a = [with((dynamic)null), null]; Diagnostic(ErrorCode.ERR_CollectionArgumentsDynamicBinding, "(dynamic)null").WithLocation(7, 19)); } [Fact] public void TypeInference_List() { string source = """ using System.Collections.Generic; class Program { static void Main() { Identity([with()]); Identity([with(capacity: 1), default]); Identity([with(capacity: 1), 3]); Identity([with(collection: [default, 2]), default]); Identity([with(collection: [default]), default, 3]); } static List<T> Identity<T>(List<T> c) => c; } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (6,9): error CS0411: The type arguments for method 'Program.Identity<T>(List<T>)' cannot be inferred from the usage. Try specifying the type arguments explicitly. // Identity([with()]); Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "Identity").WithArguments("Program.Identity<T>(System.Collections.Generic.List<T>)").WithLocation(6, 9), // (7,9): error CS0411: The type arguments for method 'Program.Identity<T>(List<T>)' cannot be inferred from the usage. Try specifying the type arguments explicitly. // Identity([with(capacity: 1), default]); Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "Identity").WithArguments("Program.Identity<T>(System.Collections.Generic.List<T>)").WithLocation(7, 9), // (9,9): error CS0411: The type arguments for method 'Program.Identity<T>(List<T>)' cannot be inferred from the usage. Try specifying the type arguments explicitly. // Identity([with(collection: [default, 2]), default]); Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "Identity").WithArguments("Program.Identity<T>(System.Collections.Generic.List<T>)").WithLocation(9, 9)); } [Fact] public void TypeInference_CollectionInitializer() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; class MyCollection<T> : IEnumerable<T> { private readonly List<T> _items; public MyCollection(params T[] args) { _items = new(args); } public void Add(T t) { _items.Add(t); } IEnumerator<T> IEnumerable<T>.GetEnumerator() => _items.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => _items.GetEnumerator(); } """; string sourceB = """ class Program { static void Main() { Identity([with()]); Identity([with(default, 2), default]); Identity([with(default), default, 3]); } static MyCollection<T> Identity<T>(MyCollection<T> c) => c; } """; var comp = CreateCompilation([sourceA, sourceB]); comp.VerifyEmitDiagnostics( // (5,9): error CS0411: The type arguments for method 'Program.Identity<T>(MyCollection<T>)' cannot be inferred from the usage. Try specifying the type arguments explicitly. // Identity([with()]); Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "Identity").WithArguments("Program.Identity<T>(MyCollection<T>)").WithLocation(5, 9), // (6,9): error CS0411: The type arguments for method 'Program.Identity<T>(MyCollection<T>)' cannot be inferred from the usage. Try specifying the type arguments explicitly. // Identity([with(default, 2), default]); Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "Identity").WithArguments("Program.Identity<T>(MyCollection<T>)").WithLocation(6, 9)); } #if DICTIONARY_EXPRESSIONS [Fact] public void InterfaceTarget_ReorderedArguments() { string source = """ using System; using System.Collections.Generic; class Program { static void Main() { Create<int, string>(EqualityComparer<int>.Default, 2, new(1, "one")).Report(); } static IDictionary<K, V> Create<K, V>(IEqualityComparer<K> e, int c, KeyValuePair<K, V> x) { return [with(comparer: Identity(e), capacity: Identity(c)), Identity(x)]; } static T Identity<T>(T value) { Console.WriteLine(value); return value; } } """; var verifier = CompileAndVerify( [source, s_collectionExtensions], expectedOutput: """ System.Collections.Generic.GenericEqualityComparer`1[System.Int32] 2 [1, one] [[1, one]], """); verifier.VerifyDiagnostics(); verifier.VerifyIL("Program.Create<K, V>", """ { // Code size 47 (0x2f) .maxstack 4 .locals init (System.Collections.Generic.KeyValuePair<K, V> V_0, System.Collections.Generic.IEqualityComparer<K> V_1) IL_0000: ldarg.0 IL_0001: call "System.Collections.Generic.IEqualityComparer<K> Program.Identity<System.Collections.Generic.IEqualityComparer<K>>(System.Collections.Generic.IEqualityComparer<K>)" IL_0006: stloc.1 IL_0007: ldarg.1 IL_0008: call "int Program.Identity<int>(int)" IL_000d: ldloc.1 IL_000e: newobj "System.Collections.Generic.Dictionary<K, V>..ctor(int, System.Collections.Generic.IEqualityComparer<K>)" IL_0013: ldarg.2 IL_0014: call "System.Collections.Generic.KeyValuePair<K, V> Program.Identity<System.Collections.Generic.KeyValuePair<K, V>>(System.Collections.Generic.KeyValuePair<K, V>)" IL_0019: stloc.0 IL_001a: dup IL_001b: ldloca.s V_0 IL_001d: call "K System.Collections.Generic.KeyValuePair<K, V>.Key.get" IL_0022: ldloca.s V_0 IL_0024: call "V System.Collections.Generic.KeyValuePair<K, V>.Value.get" IL_0029: callvirt "void System.Collections.Generic.Dictionary<K, V>.this[K].set" IL_002e: ret } """); } [Fact] public void InterfaceTarget_Dynamic() { string source = """ using System.Collections.Generic; class Program { static void Main() { CreateReadOnlyDictionary(null, 1, "one"); CreateDictionary(2, null, 2, "two"); } static IReadOnlyDictionary<K, V> CreateReadOnlyDictionary<K, V>(dynamic d, K k, V v) { return [with(d), k:v]; } static IDictionary<K, V> CreateDictionary<K, V>(dynamic x, dynamic y, K k, V v) { return [with(x, y), k:v]; } } """; var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); comp.VerifyEmitDiagnostics( // (11,22): error CS9503: Collection arguments cannot be dynamic; compile-time binding is required. // return [with(d), k:v]; Diagnostic(ErrorCode.ERR_CollectionArgumentsDynamicBinding, "d").WithLocation(11, 22), // (15,22): error CS9503: Collection arguments cannot be dynamic; compile-time binding is required. // return [with(x, y), k:v]; Diagnostic(ErrorCode.ERR_CollectionArgumentsDynamicBinding, "x").WithLocation(15, 22), // (15,25): error CS9503: Collection arguments cannot be dynamic; compile-time binding is required. // return [with(x, y), k:v]; Diagnostic(ErrorCode.ERR_CollectionArgumentsDynamicBinding, "y").WithLocation(15, 25)); } [Theory] [CombinatorialData] public void InterfaceTarget_FieldInitializer( [CombinatorialValues("IDictionary", "IReadOnlyDictionary")] string typeName) { string source = $$""" using System.Collections.Generic; class C<K, V> { public {{typeName}}<K, V> F = [with(GetComparer())]; static IEqualityComparer<K> GetComparer() => null; } class Program { static void Main() { var c = new C<int, string>(); c.F.Report(); } } """; var verifier = CompileAndVerify( [source, s_collectionExtensions], expectedOutput: "[], "); verifier.VerifyDiagnostics(); verifier.VerifyIL("C<K, V>..ctor", typeName == "IDictionary" ? """ { // Code size 23 (0x17) .maxstack 2 IL_0000: ldarg.0 IL_0001: call "System.Collections.Generic.IEqualityComparer<K> C<K, V>.GetComparer()" IL_0006: newobj "System.Collections.Generic.Dictionary<K, V>..ctor(System.Collections.Generic.IEqualityComparer<K>)" IL_000b: stfld "System.Collections.Generic.IDictionary<K, V> C<K, V>.F" IL_0010: ldarg.0 IL_0011: call "object..ctor()" IL_0016: ret } """ : """ { // Code size 28 (0x1c) .maxstack 2 IL_0000: ldarg.0 IL_0001: call "System.Collections.Generic.IEqualityComparer<K> C<K, V>.GetComparer()" IL_0006: newobj "System.Collections.Generic.Dictionary<K, V>..ctor(System.Collections.Generic.IEqualityComparer<K>)" IL_000b: newobj "System.Collections.ObjectModel.ReadOnlyDictionary<K, V>..ctor(System.Collections.Generic.IDictionary<K, V>)" IL_0010: stfld "System.Collections.Generic.IReadOnlyDictionary<K, V> C<K, V>.F" IL_0015: ldarg.0 IL_0016: call "object..ctor()" IL_001b: ret } """); } [Theory] [CombinatorialData] public void InterfaceTarget_Nullability( [CombinatorialValues("IDictionary", "IReadOnlyDictionary")] string typeName) { string source = $$""" #nullable enable using System.Collections.Generic; class Program { static {{typeName}}<K, V> Create1<K, V>(bool b, IEqualityComparer<K>? c1) { if (b) return new Dictionary<K, V>(c1); return [with(c1)]; } static {{typeName}}<K, V> Create2<K, V>(bool b, IEqualityComparer<K?> c2) where K : class { if (b) return new Dictionary<K, V>(c2); return [with(c2)]; } static {{typeName}}<K?, V> Create3<K, V>(bool b, IEqualityComparer<K> c3) where K : class { if (b) return new Dictionary<K?, V>(c3); return [with(c3)]; } } """; var comp = CreateCompilation(source); // https://github.com/dotnet/roslyn/issues/81860 // Handle collection arguments in flow analysis: report CS8620 for 'with(c3)'. comp.VerifyEmitDiagnostics( // (17,45): warning CS8620: Argument of type 'IEqualityComparer<K>' cannot be used for parameter 'comparer' of type 'IEqualityComparer<K?>' in 'Dictionary<K?, V>.Dictionary(IEqualityComparer<K?> comparer)' due to differences in the nullability of reference types. // if (b) return new Dictionary<K?, V>(c3); Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgument, "c3").WithArguments("System.Collections.Generic.IEqualityComparer<K>", "System.Collections.Generic.IEqualityComparer<K?>", "comparer", "Dictionary<K?, V>.Dictionary(IEqualityComparer<K?> comparer)").WithLocation(17, 45)); } [Theory] [CombinatorialData] public void InterfaceTarget_GenericMethod( [CombinatorialValues("IDictionary", "IReadOnlyDictionary")] string typeName) { string source = $$""" using System.Collections.Generic; class Program { static {{typeName}}<K, V> Create<K, V>(IEqualityComparer<K> e) { return [with(e)]; } static void Main() { Create<int, string>(null).Report(); } } """; var verifier = CompileAndVerify( [source, s_collectionExtensions], expectedOutput: "[], "); verifier.VerifyDiagnostics(); verifier.VerifyIL("Program.Create<K, V>", typeName == "IDictionary" ? """ { // Code size 7 (0x7) .maxstack 1 IL_0000: ldarg.0 IL_0001: newobj "System.Collections.Generic.Dictionary<K, V>..ctor(System.Collections.Generic.IEqualityComparer<K>)" IL_0006: ret } """ : """ { // Code size 12 (0xc) .maxstack 1 IL_0000: ldarg.0 IL_0001: newobj "System.Collections.Generic.Dictionary<K, V>..ctor(System.Collections.Generic.IEqualityComparer<K>)" IL_0006: newobj "System.Collections.ObjectModel.ReadOnlyDictionary<K, V>..ctor(System.Collections.Generic.IDictionary<K, V>)" IL_000b: ret } """); } [Theory] [CombinatorialData] public void InterfaceTarget_DictionaryInterfaces( [CombinatorialValues("IDictionary", "IReadOnlyDictionary")] string typeName) { string sourceA = $$""" using System.Collections.Generic; class Program { static void Main() { Create<int, string>(1, "one", new(2, "two")).Report(); } static {{typeName}}<K, V> Create<K, V>(K k, V v, KeyValuePair<K, V> x) { return [with(), k:v, x]; } } """; var comp = CreateCompilation( [sourceA, s_collectionExtensions], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify( comp, expectedOutput: "[[1, one], [2, two]], "); verifier.VerifyDiagnostics(); verifier.VerifyIL("Program.Create<K, V>", (typeName is "IDictionary") ? """ { // Code size 36 (0x24) .maxstack 4 .locals init (System.Collections.Generic.KeyValuePair<K, V> V_0) IL_0000: newobj "System.Collections.Generic.Dictionary<K, V>..ctor()" IL_0005: dup IL_0006: ldarg.0 IL_0007: ldarg.1 IL_0008: callvirt "void System.Collections.Generic.Dictionary<K, V>.this[K].set" IL_000d: ldarg.2 IL_000e: stloc.0 IL_000f: dup IL_0010: ldloca.s V_0 IL_0012: call "K System.Collections.Generic.KeyValuePair<K, V>.Key.get" IL_0017: ldloca.s V_0 IL_0019: call "V System.Collections.Generic.KeyValuePair<K, V>.Value.get" IL_001e: callvirt "void System.Collections.Generic.Dictionary<K, V>.this[K].set" IL_0023: ret } """ : """ { // Code size 41 (0x29) .maxstack 4 .locals init (System.Collections.Generic.KeyValuePair<K, V> V_0) IL_0000: newobj "System.Collections.Generic.Dictionary<K, V>..ctor()" IL_0005: dup IL_0006: ldarg.0 IL_0007: ldarg.1 IL_0008: callvirt "void System.Collections.Generic.Dictionary<K, V>.this[K].set" IL_000d: ldarg.2 IL_000e: stloc.0 IL_000f: dup IL_0010: ldloca.s V_0 IL_0012: call "K System.Collections.Generic.KeyValuePair<K, V>.Key.get" IL_0017: ldloca.s V_0 IL_0019: call "V System.Collections.Generic.KeyValuePair<K, V>.Value.get" IL_001e: callvirt "void System.Collections.Generic.Dictionary<K, V>.this[K].set" IL_0023: newobj "System.Collections.ObjectModel.ReadOnlyDictionary<K, V>..ctor(System.Collections.Generic.IDictionary<K, V>)" IL_0028: ret } """); string sourceB = $$""" using System.Collections.Generic; class Program { static void Main() { Create1<int, string>(3, 1, "one", new(2, "two")).Report(); Create2<int, string>(1, 3, "three", new(4, "four")).Report(); } static {{typeName}}<K, V> Create1<K, V>(int c, K k, V v, KeyValuePair<K, V> x) { return [with(c), k:v, x]; } static {{typeName}}<K, V> Create2<K, V>(int c, K k, V v, KeyValuePair<K, V> x) { return [with(capacity: c), k:v, x]; } } """; comp = CreateCompilation( [sourceB, s_collectionExtensions], options: TestOptions.ReleaseExe); string expectedIL; if (typeName is "IDictionary") { verifier = CompileAndVerify( comp, expectedOutput: "[[1, one], [2, two]], [[3, three], [4, four]], "); verifier.VerifyDiagnostics(); expectedIL = """ { // Code size 37 (0x25) .maxstack 4 .locals init (System.Collections.Generic.KeyValuePair<K, V> V_0) IL_0000: ldarg.0 IL_0001: newobj "System.Collections.Generic.Dictionary<K, V>..ctor(int)" IL_0006: dup IL_0007: ldarg.1 IL_0008: ldarg.2 IL_0009: callvirt "void System.Collections.Generic.Dictionary<K, V>.this[K].set" IL_000e: ldarg.3 IL_000f: stloc.0 IL_0010: dup IL_0011: ldloca.s V_0 IL_0013: call "K System.Collections.Generic.KeyValuePair<K, V>.Key.get" IL_0018: ldloca.s V_0 IL_001a: call "V System.Collections.Generic.KeyValuePair<K, V>.Value.get" IL_001f: callvirt "void System.Collections.Generic.Dictionary<K, V>.this[K].set" IL_0024: ret } """; verifier.VerifyIL("Program.Create1<K, V>", expectedIL); verifier.VerifyIL("Program.Create2<K, V>", expectedIL); } else { comp.VerifyEmitDiagnostics( // (11,22): error CS1503: Argument 1: cannot convert from 'int' to 'System.Collections.Generic.IEqualityComparer<K>?' // return [with(c), k:v, x]; Diagnostic(ErrorCode.ERR_BadArgType, "c").WithArguments("1", "int", "System.Collections.Generic.IEqualityComparer<K>?").WithLocation(11, 22), // (15,22): error CS1739: The best overload for '<signature>' does not have a parameter named 'capacity' // return [with(capacity: c), k:v, x]; Diagnostic(ErrorCode.ERR_BadNamedArgument, "capacity").WithArguments("<signature>", "capacity").WithLocation(15, 22)); } string sourceC = $$""" using System.Collections.Generic; class Program { static void Main() { Create1<int, string>(null, 1, "one", new(2, "two")).Report(); Create2<int, string>(null, 3, "three", new(4, "four")).Report(); } static {{typeName}}<K, V> Create1<K, V>(IEqualityComparer<K> e, K k, V v, KeyValuePair<K, V> x) { return [with(e), k:v, x]; } static {{typeName}}<K, V> Create2<K, V>(IEqualityComparer<K> e, K k, V v, KeyValuePair<K, V> x) { return [with(comparer: e), k:v, x]; } } """; comp = CreateCompilation( [sourceC, s_collectionExtensions], options: TestOptions.ReleaseExe); verifier = CompileAndVerify( comp, expectedOutput: "[[1, one], [2, two]], [[3, three], [4, four]], "); verifier.VerifyDiagnostics(); expectedIL = (typeName is "IDictionary") ? """ { // Code size 37 (0x25) .maxstack 4 .locals init (System.Collections.Generic.KeyValuePair<K, V> V_0) IL_0000: ldarg.0 IL_0001: newobj "System.Collections.Generic.Dictionary<K, V>..ctor(System.Collections.Generic.IEqualityComparer<K>)" IL_0006: dup IL_0007: ldarg.1 IL_0008: ldarg.2 IL_0009: callvirt "void System.Collections.Generic.Dictionary<K, V>.this[K].set" IL_000e: ldarg.3 IL_000f: stloc.0 IL_0010: dup IL_0011: ldloca.s V_0 IL_0013: call "K System.Collections.Generic.KeyValuePair<K, V>.Key.get" IL_0018: ldloca.s V_0 IL_001a: call "V System.Collections.Generic.KeyValuePair<K, V>.Value.get" IL_001f: callvirt "void System.Collections.Generic.Dictionary<K, V>.this[K].set" IL_0024: ret } """ : """ { // Code size 42 (0x2a) .maxstack 4 .locals init (System.Collections.Generic.KeyValuePair<K, V> V_0) IL_0000: ldarg.0 IL_0001: newobj "System.Collections.Generic.Dictionary<K, V>..ctor(System.Collections.Generic.IEqualityComparer<K>)" IL_0006: dup IL_0007: ldarg.1 IL_0008: ldarg.2 IL_0009: callvirt "void System.Collections.Generic.Dictionary<K, V>.this[K].set" IL_000e: ldarg.3 IL_000f: stloc.0 IL_0010: dup IL_0011: ldloca.s V_0 IL_0013: call "K System.Collections.Generic.KeyValuePair<K, V>.Key.get" IL_0018: ldloca.s V_0 IL_001a: call "V System.Collections.Generic.KeyValuePair<K, V>.Value.get" IL_001f: callvirt "void System.Collections.Generic.Dictionary<K, V>.this[K].set" IL_0024: newobj "System.Collections.ObjectModel.ReadOnlyDictionary<K, V>..ctor(System.Collections.Generic.IDictionary<K, V>)" IL_0029: ret } """; verifier.VerifyIL("Program.Create1<K, V>", expectedIL); verifier.VerifyIL("Program.Create2<K, V>", expectedIL); string sourceD = $$""" using System.Collections.Generic; class Program { static void Main() { Create1<int, string>(null, 3, 1, "one", new(2, "two")).Report(); Create2<int, string>(null, 1, 3, "three", new(4, "four")).Report(); } static {{typeName}}<K, V> Create1<K, V>(IEqualityComparer<K> e, int c, K k, V v, KeyValuePair<K, V> x) { return [with(c, e), k:v, x]; } static {{typeName}}<K, V> Create2<K, V>(IEqualityComparer<K> e, int c, K k, V v, KeyValuePair<K, V> x) { return [with(capacity: c, comparer: e), k:v, x]; } } """; comp = CreateCompilation( [sourceD, s_collectionExtensions], options: TestOptions.ReleaseExe); if (typeName is "IDictionary") { verifier = CompileAndVerify( comp, expectedOutput: "[[1, one], [2, two]], [[3, three], [4, four]], "); verifier.VerifyDiagnostics(); expectedIL = """ { // Code size 39 (0x27) .maxstack 4 .locals init (System.Collections.Generic.KeyValuePair<K, V> V_0) IL_0000: ldarg.1 IL_0001: ldarg.0 IL_0002: newobj "System.Collections.Generic.Dictionary<K, V>..ctor(int, System.Collections.Generic.IEqualityComparer<K>)" IL_0007: dup IL_0008: ldarg.2 IL_0009: ldarg.3 IL_000a: callvirt "void System.Collections.Generic.Dictionary<K, V>.this[K].set" IL_000f: ldarg.s V_4 IL_0011: stloc.0 IL_0012: dup IL_0013: ldloca.s V_0 IL_0015: call "K System.Collections.Generic.KeyValuePair<K, V>.Key.get" IL_001a: ldloca.s V_0 IL_001c: call "V System.Collections.Generic.KeyValuePair<K, V>.Value.get" IL_0021: callvirt "void System.Collections.Generic.Dictionary<K, V>.this[K].set" IL_0026: ret } """; verifier.VerifyIL("Program.Create1<K, V>", expectedIL); verifier.VerifyIL("Program.Create2<K, V>", expectedIL); } else { comp.VerifyEmitDiagnostics( // (11,16): error CS1501: No overload for method '<signature>' takes 2 arguments // return [with(c, e), k:v, x]; Diagnostic(ErrorCode.ERR_BadArgCount, "[with(c, e), k:v, x]").WithArguments("<signature>", "2").WithLocation(11, 16), // (15,22): error CS1739: The best overload for '<signature>' does not have a parameter named 'capacity' // return [with(capacity: c, comparer: e), k:v, x]; Diagnostic(ErrorCode.ERR_BadNamedArgument, "capacity").WithArguments("<signature>", "capacity").WithLocation(15, 22)); } string sourceE = $$""" using System.Collections.Generic; class Program { static {{typeName}}<K, V> Create1<K, V>(IEnumerable<KeyValuePair<K, V>> c, K k, V v) { return [with(c), k:v]; } static {{typeName}}<K, V> Create2<K, V>(IEnumerable<KeyValuePair<K, V>> c, K k, V v) { return [with(collection: c), k:v]; } } """; comp = CreateCompilation(sourceE); comp.VerifyEmitDiagnostics( // (6,22): error CS1503: Argument 1: cannot convert from 'System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<K, V>>' to 'System.Collections.Generic.IEqualityComparer<K>?' // return [with(c), k:v]; Diagnostic(ErrorCode.ERR_BadArgType, "c").WithArguments("1", "System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<K, V>>", "System.Collections.Generic.IEqualityComparer<K>?").WithLocation(6, 22), // (10,22): error CS1739: The best overload for '<signature>' does not have a parameter named 'collection' // return [with(collection: c), k:v]; Diagnostic(ErrorCode.ERR_BadNamedArgument, "collection").WithArguments("<signature>", "collection").WithLocation(10, 22)); } [Theory] [CombinatorialData] public void CollectionArguments_CapacityAndComparer_02( [CombinatorialValues( "System.Collections.Generic.IReadOnlyDictionary<K, V>", "System.Collections.Generic.IDictionary<K, V>")] string typeName) { string source = $$""" using System.Collections.Generic; class Program { static void Create<K, V>(int capacity, IEqualityComparer<K> comparer) { {{typeName}} c; c = []; c = [with()]; c = [with(default)]; c = [with(capacity)]; c = [with(comparer)]; c = [with(capacity, comparer)]; } } """; var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); switch (typeName) { case "System.Collections.Generic.IReadOnlyDictionary<K, V>": comp.VerifyEmitDiagnostics( // (10,19): error CS1503: Argument 1: cannot convert from 'int' to 'System.Collections.Generic.IEqualityComparer<K>?' // c = [with(capacity)]; Diagnostic(ErrorCode.ERR_BadArgType, "capacity").WithArguments("1", "int", "System.Collections.Generic.IEqualityComparer<K>?").WithLocation(10, 19), // (12,13): error CS1501: No overload for method '<signature>' takes 2 arguments // c = [with(capacity, comparer)]; Diagnostic(ErrorCode.ERR_BadArgCount, "[with(capacity, comparer)]").WithArguments("<signature>", "2").WithLocation(12, 13)); break; case "System.Collections.Generic.IDictionary<K, V>": comp.VerifyEmitDiagnostics( // (9,13): error CS0121: The call is ambiguous between the following methods or properties: 'Program.<signature>(IEqualityComparer<K>?)' and 'Program.<signature>(int)' // c = [with(default)]; Diagnostic(ErrorCode.ERR_AmbigCall, "[with(default)]").WithArguments("Program.<signature>(System.Collections.Generic.IEqualityComparer<K>?)", "Program.<signature>(int)").WithLocation(9, 13)); break; default: throw ExceptionUtilities.UnexpectedValue(typeName); } } [Theory] [InlineData("IDictionary")] [InlineData("IReadOnlyDictionary")] public void EmptyArguments_DictionaryInterface(string interfaceType) { string source = $$""" using System.Collections.Generic; class Program { static void Main() { NoArgs<string, int>().Report(); EmptyArgs<string, int>().Report(); } static {{interfaceType}}<K, V> NoArgs<K, V>() => []; static {{interfaceType}}<K, V> EmptyArgs<K, V>() => [with()]; } """; var verifier = CompileAndVerify( [source, s_collectionExtensions], verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("[], [], ")); verifier.VerifyDiagnostics(); string expectedIL = (interfaceType == "IReadOnlyDictionary") ? """ { // Code size 11 (0xb) .maxstack 1 IL_0000: newobj "System.Collections.Generic.Dictionary<K, V>..ctor()" IL_0005: newobj "System.Collections.ObjectModel.ReadOnlyDictionary<K, V>..ctor(System.Collections.Generic.IDictionary<K, V>)" IL_000a: ret } """ : """ { // Code size 6 (0x6) .maxstack 1 IL_0000: newobj "System.Collections.Generic.Dictionary<K, V>..ctor()" IL_0005: ret } """; verifier.VerifyIL("Program.NoArgs<K, V>", expectedIL); verifier.VerifyIL("Program.EmptyArgs<K, V>", expectedIL); } [Theory] [InlineData("IDictionary")] [InlineData("IReadOnlyDictionary")] public void Arguments_DictionaryInterface(string interfaceType) { string sourceA = $$""" using System.Collections.Generic; class Program { static void Main() { Pair(null, 1, "one").Report(); } static {{interfaceType}}<K, V> Pair<K, V>(IEqualityComparer<K> c, K k, V v) { return [with(c), k:v]; } } """; var comp = CreateCompilation([sourceA, s_collectionExtensions], options: TestOptions.ReleaseExe); comp.VerifyDiagnostics(); var verifier = CompileAndVerify( comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("[[1, one]], ")); verifier.VerifyIL("Program.Pair<K, V>", (interfaceType == "IReadOnlyDictionary") ? """ { // Code size 20 (0x14) .maxstack 4 IL_0000: ldarg.0 IL_0001: newobj "System.Collections.Generic.Dictionary<K, V>..ctor(System.Collections.Generic.IEqualityComparer<K>)" IL_0006: dup IL_0007: ldarg.1 IL_0008: ldarg.2 IL_0009: callvirt "void System.Collections.Generic.Dictionary<K, V>.this[K].set" IL_000e: newobj "System.Collections.ObjectModel.ReadOnlyDictionary<K, V>..ctor(System.Collections.Generic.IDictionary<K, V>)" IL_0013: ret } """ : """ { // Code size 15 (0xf) .maxstack 4 IL_0000: ldarg.0 IL_0001: newobj "System.Collections.Generic.Dictionary<K, V>..ctor(System.Collections.Generic.IEqualityComparer<K>)" IL_0006: dup IL_0007: ldarg.1 IL_0008: ldarg.2 IL_0009: callvirt "void System.Collections.Generic.Dictionary<K, V>.this[K].set" IL_000e: ret } """); string sourceB = $$""" using System.Collections.Generic; class Program { static void Main() { Expression(null, new KeyValuePair<int, string>(2, "two")).Report(); } static {{interfaceType}}<K, V> Expression<K, V>(IEqualityComparer<K> c, KeyValuePair<K, V> e) { return [with(1, c), e]; } } """; comp = CreateCompilation([sourceB, s_collectionExtensions], options: TestOptions.ReleaseExe); if (interfaceType == "IReadOnlyDictionary") { comp.VerifyDiagnostics( // (10,16): error CS1501: No overload for method '<signature>' takes 2 arguments // return [with(1, c), e]; Diagnostic(ErrorCode.ERR_BadArgCount, "[with(1, c), e]").WithArguments("<signature>", "2").WithLocation(10, 16)); } else { comp.VerifyDiagnostics(); verifier = CompileAndVerify( comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("[[2, two]], ")); verifier.VerifyIL("Program.Expression<K, V>", """ { // Code size 30 (0x1e) .maxstack 4 .locals init (System.Collections.Generic.KeyValuePair<K, V> V_0) IL_0000: ldc.i4.1 IL_0001: ldarg.0 IL_0002: newobj "System.Collections.Generic.Dictionary<K, V>..ctor(int, System.Collections.Generic.IEqualityComparer<K>)" IL_0007: ldarg.1 IL_0008: stloc.0 IL_0009: dup IL_000a: ldloca.s V_0 IL_000c: call "K System.Collections.Generic.KeyValuePair<K, V>.Key.get" IL_0011: ldloca.s V_0 IL_0013: call "V System.Collections.Generic.KeyValuePair<K, V>.Value.get" IL_0018: callvirt "void System.Collections.Generic.Dictionary<K, V>.this[K].set" IL_001d: ret } """); } string sourceC = $$""" using System.Collections.Generic; class Program { static {{interfaceType}}<K, V> Pair<K, V>(IEqualityComparer<K> c, K k, V v) { return [k:v, with(c)]; } } """; comp = CreateCompilation(sourceC); comp.VerifyEmitDiagnostics( // (6,22): error CS9501: Collection argument element must be the first element. // return [k:v, with(1)]; Diagnostic(ErrorCode.ERR_CollectionArgumentsMustBeFirst, "with").WithLocation(6, 22)); } [Theory] [CombinatorialData] public void InterfaceTarget_MissingMember_01( [CombinatorialValues( "IEnumerable", "IReadOnlyCollection", "IReadOnlyList", "ICollection", "IList")] string typeName, [CombinatorialValues( 0, WellKnownMember.System_Collections_Generic_List_T__ctor, WellKnownMember.System_Collections_Generic_List_T__ctorInt32, WellKnownMember.System_Collections_Generic_Dictionary_KV__ctor, WellKnownMember.System_Collections_Generic_Dictionary_KV__ctor_IEqualityComparer_K, WellKnownMember.System_Collections_Generic_Dictionary_KV__ctor_Int32, WellKnownMember.System_Collections_Generic_Dictionary_KV__ctor_Int32_IEqualityComparer_K)] int missingMember) { string source = $$""" using System.Collections.Generic; class Program { static void Create(int i) { {{typeName}}<int> c; c = []; c = [with()]; c = [with(i)]; } } """; var comp = CreateCompilation(source); comp.MakeMemberMissing((WellKnownMember)missingMember); if (typeName is "ICollection" or "IList") { switch ((WellKnownMember)missingMember) { case WellKnownMember.System_Collections_Generic_List_T__ctor: comp.VerifyEmitDiagnostics( // (7,13): error CS0656: Missing compiler required member 'System.Collections.Generic.List`1..ctor' // c = []; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[]").WithArguments("System.Collections.Generic.List`1", ".ctor").WithLocation(7, 13), // (7,13): error CS7036: There is no argument given that corresponds to the required parameter 'capacity' of 'Program.<signature>(int)' // c = []; Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "[]").WithArguments("capacity", "Program.<signature>(int)").WithLocation(7, 13), // (8,13): error CS0656: Missing compiler required member 'System.Collections.Generic.List`1..ctor' // c = [with()]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[with()]").WithArguments("System.Collections.Generic.List`1", ".ctor").WithLocation(8, 13), // (8,13): error CS7036: There is no argument given that corresponds to the required parameter 'capacity' of 'Program.<signature>(int)' // c = [with()]; Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "[with()]").WithArguments("capacity", "Program.<signature>(int)").WithLocation(8, 13), // (9,13): error CS0656: Missing compiler required member 'System.Collections.Generic.List`1..ctor' // c = [with(i)]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[with(i)]").WithArguments("System.Collections.Generic.List`1", ".ctor").WithLocation(9, 13)); break; case WellKnownMember.System_Collections_Generic_List_T__ctorInt32: comp.VerifyEmitDiagnostics( // (7,13): error CS0656: Missing compiler required member 'System.Collections.Generic.List`1..ctor' // c = []; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[]").WithArguments("System.Collections.Generic.List`1", ".ctor").WithLocation(7, 13), // (8,13): error CS0656: Missing compiler required member 'System.Collections.Generic.List`1..ctor' // c = [with()]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[with()]").WithArguments("System.Collections.Generic.List`1", ".ctor").WithLocation(8, 13), // (9,13): error CS0656: Missing compiler required member 'System.Collections.Generic.List`1..ctor' // c = [with(i)]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[with(i)]").WithArguments("System.Collections.Generic.List`1", ".ctor").WithLocation(9, 13), // (9,13): error CS1501: No overload for method '<signature>' takes 1 arguments // c = [with(i)]; Diagnostic(ErrorCode.ERR_BadArgCount, "[with(i)]").WithArguments("<signature>", "1").WithLocation(9, 13)); break; default: comp.VerifyEmitDiagnostics(); break; } } else { switch ((WellKnownMember)missingMember) { case WellKnownMember.System_Collections_Generic_List_T__ctor: comp.VerifyEmitDiagnostics( // (7,13): error CS0656: Missing compiler required member 'System.Collections.Generic.List`1..ctor' // c = []; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[]").WithArguments("System.Collections.Generic.List`1", ".ctor").WithLocation(7, 13), // (8,13): error CS0656: Missing compiler required member 'System.Collections.Generic.List`1..ctor' // c = [with()]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[with()]").WithArguments("System.Collections.Generic.List`1", ".ctor").WithLocation(8, 13), // (9,13): error CS0656: Missing compiler required member 'System.Collections.Generic.List`1..ctor' // c = [with(i)]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[with(i)]").WithArguments("System.Collections.Generic.List`1", ".ctor").WithLocation(9, 13)); break; default: comp.VerifyEmitDiagnostics( // (9,13): error CS1501: No overload for method '<signature>' takes 1 arguments // c = [with(i)]; Diagnostic(ErrorCode.ERR_BadArgCount, "[with(i)]").WithArguments("<signature>", "1").WithLocation(9, 13)); break; } } } [Theory] [CombinatorialData] public void InterfaceTarget_MissingMember_02( [CombinatorialValues( "IDictionary", "IReadOnlyDictionary")] string typeName, [CombinatorialValues( 0, WellKnownMember.System_Collections_Generic_List_T__ctor, WellKnownMember.System_Collections_Generic_List_T__ctorInt32, WellKnownMember.System_Collections_Generic_Dictionary_KV__ctor, WellKnownMember.System_Collections_Generic_Dictionary_KV__ctor_IEqualityComparer_K, WellKnownMember.System_Collections_Generic_Dictionary_KV__ctor_Int32, WellKnownMember.System_Collections_Generic_Dictionary_KV__ctor_Int32_IEqualityComparer_K)] int missingMember) { string source = $$""" using System.Collections.Generic; class Program { static void Create(int i, IEqualityComparer<int> e) { {{typeName}}<int, string> c; c = []; c = [with()]; c = [with(i)]; c = [with(e)]; c = [with(i, e)]; } } """; var comp = CreateCompilation(source); comp.MakeMemberMissing((WellKnownMember)missingMember); if (typeName is "IDictionary") { switch ((WellKnownMember)missingMember) { case WellKnownMember.System_Collections_Generic_Dictionary_KV__ctor: comp.VerifyEmitDiagnostics( // (7,13): error CS0656: Missing compiler required member 'System.Collections.Generic.Dictionary`2..ctor' // c = []; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[]").WithArguments("System.Collections.Generic.Dictionary`2", ".ctor").WithLocation(7, 13), // (7,13): error CS0656: Missing compiler required member 'System.Collections.Generic.Dictionary`2..ctor' // c = []; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[]").WithArguments("System.Collections.Generic.Dictionary`2", ".ctor").WithLocation(7, 13), // (7,13): error CS1501: No overload for method '<signature>' takes 0 arguments // c = []; Diagnostic(ErrorCode.ERR_BadArgCount, "[]").WithArguments("<signature>", "0").WithLocation(7, 13), // (8,13): error CS0656: Missing compiler required member 'System.Collections.Generic.Dictionary`2..ctor' // c = [with()]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[with()]").WithArguments("System.Collections.Generic.Dictionary`2", ".ctor").WithLocation(8, 13), // (8,13): error CS0656: Missing compiler required member 'System.Collections.Generic.Dictionary`2..ctor' // c = [with()]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[with()]").WithArguments("System.Collections.Generic.Dictionary`2", ".ctor").WithLocation(8, 13), // (8,13): error CS1501: No overload for method '<signature>' takes 0 arguments // c = [with()]; Diagnostic(ErrorCode.ERR_BadArgCount, "[with()]").WithArguments("<signature>", "0").WithLocation(8, 13), // (9,13): error CS0656: Missing compiler required member 'System.Collections.Generic.Dictionary`2..ctor' // c = [with(i)]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[with(i)]").WithArguments("System.Collections.Generic.Dictionary`2", ".ctor").WithLocation(9, 13), // (9,13): error CS0656: Missing compiler required member 'System.Collections.Generic.Dictionary`2..ctor' // c = [with(i)]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[with(i)]").WithArguments("System.Collections.Generic.Dictionary`2", ".ctor").WithLocation(9, 13), // (10,13): error CS0656: Missing compiler required member 'System.Collections.Generic.Dictionary`2..ctor' // c = [with(e)]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[with(e)]").WithArguments("System.Collections.Generic.Dictionary`2", ".ctor").WithLocation(10, 13), // (10,13): error CS0656: Missing compiler required member 'System.Collections.Generic.Dictionary`2..ctor' // c = [with(e)]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[with(e)]").WithArguments("System.Collections.Generic.Dictionary`2", ".ctor").WithLocation(10, 13), // (11,13): error CS0656: Missing compiler required member 'System.Collections.Generic.Dictionary`2..ctor' // c = [with(i, e)]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[with(i, e)]").WithArguments("System.Collections.Generic.Dictionary`2", ".ctor").WithLocation(11, 13), // (11,13): error CS0656: Missing compiler required member 'System.Collections.Generic.Dictionary`2..ctor' // c = [with(i, e)]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[with(i, e)]").WithArguments("System.Collections.Generic.Dictionary`2", ".ctor").WithLocation(11, 13)); break; case WellKnownMember.System_Collections_Generic_Dictionary_KV__ctor_IEqualityComparer_K: comp.VerifyEmitDiagnostics( // (7,13): error CS0656: Missing compiler required member 'System.Collections.Generic.Dictionary`2..ctor' // c = []; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[]").WithArguments("System.Collections.Generic.Dictionary`2", ".ctor").WithLocation(7, 13), // (8,13): error CS0656: Missing compiler required member 'System.Collections.Generic.Dictionary`2..ctor' // c = [with()]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[with()]").WithArguments("System.Collections.Generic.Dictionary`2", ".ctor").WithLocation(8, 13), // (9,13): error CS0656: Missing compiler required member 'System.Collections.Generic.Dictionary`2..ctor' // c = [with(i)]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[with(i)]").WithArguments("System.Collections.Generic.Dictionary`2", ".ctor").WithLocation(9, 13), // (10,13): error CS0656: Missing compiler required member 'System.Collections.Generic.Dictionary`2..ctor' // c = [with(e)]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[with(e)]").WithArguments("System.Collections.Generic.Dictionary`2", ".ctor").WithLocation(10, 13), // (10,19): error CS1503: Argument 1: cannot convert from 'System.Collections.Generic.IEqualityComparer<int>' to 'int' // c = [with(e)]; Diagnostic(ErrorCode.ERR_BadArgType, "e").WithArguments("1", "System.Collections.Generic.IEqualityComparer<int>", "int").WithLocation(10, 19), // (11,13): error CS0656: Missing compiler required member 'System.Collections.Generic.Dictionary`2..ctor' // c = [with(i, e)]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[with(i, e)]").WithArguments("System.Collections.Generic.Dictionary`2", ".ctor").WithLocation(11, 13)); break; case WellKnownMember.System_Collections_Generic_Dictionary_KV__ctor_Int32: comp.VerifyEmitDiagnostics( // (7,13): error CS0656: Missing compiler required member 'System.Collections.Generic.Dictionary`2..ctor' // c = []; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[]").WithArguments("System.Collections.Generic.Dictionary`2", ".ctor").WithLocation(7, 13), // (8,13): error CS0656: Missing compiler required member 'System.Collections.Generic.Dictionary`2..ctor' // c = [with()]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[with()]").WithArguments("System.Collections.Generic.Dictionary`2", ".ctor").WithLocation(8, 13), // (9,13): error CS0656: Missing compiler required member 'System.Collections.Generic.Dictionary`2..ctor' // c = [with(i)]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[with(i)]").WithArguments("System.Collections.Generic.Dictionary`2", ".ctor").WithLocation(9, 13), // (9,19): error CS1503: Argument 1: cannot convert from 'int' to 'System.Collections.Generic.IEqualityComparer<int>?' // c = [with(i)]; Diagnostic(ErrorCode.ERR_BadArgType, "i").WithArguments("1", "int", "System.Collections.Generic.IEqualityComparer<int>?").WithLocation(9, 19), // (10,13): error CS0656: Missing compiler required member 'System.Collections.Generic.Dictionary`2..ctor' // c = [with(e)]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[with(e)]").WithArguments("System.Collections.Generic.Dictionary`2", ".ctor").WithLocation(10, 13), // (11,13): error CS0656: Missing compiler required member 'System.Collections.Generic.Dictionary`2..ctor' // c = [with(i, e)]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[with(i, e)]").WithArguments("System.Collections.Generic.Dictionary`2", ".ctor").WithLocation(11, 13)); break; case WellKnownMember.System_Collections_Generic_Dictionary_KV__ctor_Int32_IEqualityComparer_K: comp.VerifyEmitDiagnostics( // (7,13): error CS0656: Missing compiler required member 'System.Collections.Generic.Dictionary`2..ctor' // c = []; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[]").WithArguments("System.Collections.Generic.Dictionary`2", ".ctor").WithLocation(7, 13), // (8,13): error CS0656: Missing compiler required member 'System.Collections.Generic.Dictionary`2..ctor' // c = [with()]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[with()]").WithArguments("System.Collections.Generic.Dictionary`2", ".ctor").WithLocation(8, 13), // (9,13): error CS0656: Missing compiler required member 'System.Collections.Generic.Dictionary`2..ctor' // c = [with(i)]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[with(i)]").WithArguments("System.Collections.Generic.Dictionary`2", ".ctor").WithLocation(9, 13), // (10,13): error CS0656: Missing compiler required member 'System.Collections.Generic.Dictionary`2..ctor' // c = [with(e)]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[with(e)]").WithArguments("System.Collections.Generic.Dictionary`2", ".ctor").WithLocation(10, 13), // (11,13): error CS0656: Missing compiler required member 'System.Collections.Generic.Dictionary`2..ctor' // c = [with(i, e)]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[with(i, e)]").WithArguments("System.Collections.Generic.Dictionary`2", ".ctor").WithLocation(11, 13), // (11,13): error CS1501: No overload for method '<signature>' takes 2 arguments // c = [with(i, e)]; Diagnostic(ErrorCode.ERR_BadArgCount, "[with(i, e)]").WithArguments("<signature>", "2").WithLocation(11, 13)); break; default: comp.VerifyEmitDiagnostics(); break; } } else { switch ((WellKnownMember)missingMember) { case WellKnownMember.System_Collections_Generic_Dictionary_KV__ctor: comp.VerifyEmitDiagnostics( // (7,13): error CS0656: Missing compiler required member 'System.Collections.Generic.Dictionary`2..ctor' // c = []; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[]").WithArguments("System.Collections.Generic.Dictionary`2", ".ctor").WithLocation(7, 13), // (7,13): error CS0656: Missing compiler required member 'System.Collections.Generic.Dictionary`2..ctor' // c = []; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[]").WithArguments("System.Collections.Generic.Dictionary`2", ".ctor").WithLocation(7, 13), // (7,13): error CS7036: There is no argument given that corresponds to the required parameter 'comparer' of 'Program.<signature>(IEqualityComparer<int>?)' // c = []; Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "[]").WithArguments("comparer", "Program.<signature>(System.Collections.Generic.IEqualityComparer<int>?)").WithLocation(7, 13), // (8,13): error CS0656: Missing compiler required member 'System.Collections.Generic.Dictionary`2..ctor' // c = [with()]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[with()]").WithArguments("System.Collections.Generic.Dictionary`2", ".ctor").WithLocation(8, 13), // (8,13): error CS0656: Missing compiler required member 'System.Collections.Generic.Dictionary`2..ctor' // c = [with()]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[with()]").WithArguments("System.Collections.Generic.Dictionary`2", ".ctor").WithLocation(8, 13), // (8,13): error CS7036: There is no argument given that corresponds to the required parameter 'comparer' of 'Program.<signature>(IEqualityComparer<int>?)' // c = [with()]; Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "[with()]").WithArguments("comparer", "Program.<signature>(System.Collections.Generic.IEqualityComparer<int>?)").WithLocation(8, 13), // (9,13): error CS0656: Missing compiler required member 'System.Collections.Generic.Dictionary`2..ctor' // c = [with(i)]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[with(i)]").WithArguments("System.Collections.Generic.Dictionary`2", ".ctor").WithLocation(9, 13), // (9,13): error CS0656: Missing compiler required member 'System.Collections.Generic.Dictionary`2..ctor' // c = [with(i)]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[with(i)]").WithArguments("System.Collections.Generic.Dictionary`2", ".ctor").WithLocation(9, 13), // (9,19): error CS1503: Argument 1: cannot convert from 'int' to 'System.Collections.Generic.IEqualityComparer<int>?' // c = [with(i)]; Diagnostic(ErrorCode.ERR_BadArgType, "i").WithArguments("1", "int", "System.Collections.Generic.IEqualityComparer<int>?").WithLocation(9, 19), // (10,13): error CS0656: Missing compiler required member 'System.Collections.Generic.Dictionary`2..ctor' // c = [with(e)]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[with(e)]").WithArguments("System.Collections.Generic.Dictionary`2", ".ctor").WithLocation(10, 13), // (10,13): error CS0656: Missing compiler required member 'System.Collections.Generic.Dictionary`2..ctor' // c = [with(e)]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[with(e)]").WithArguments("System.Collections.Generic.Dictionary`2", ".ctor").WithLocation(10, 13), // (11,13): error CS0656: Missing compiler required member 'System.Collections.Generic.Dictionary`2..ctor' // c = [with(i, e)]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[with(i, e)]").WithArguments("System.Collections.Generic.Dictionary`2", ".ctor").WithLocation(11, 13), // (11,13): error CS0656: Missing compiler required member 'System.Collections.Generic.Dictionary`2..ctor' // c = [with(i, e)]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[with(i, e)]").WithArguments("System.Collections.Generic.Dictionary`2", ".ctor").WithLocation(11, 13), // (11,13): error CS1501: No overload for method '<signature>' takes 2 arguments // c = [with(i, e)]; Diagnostic(ErrorCode.ERR_BadArgCount, "[with(i, e)]").WithArguments("<signature>", "2").WithLocation(11, 13)); break; case WellKnownMember.System_Collections_Generic_Dictionary_KV__ctor_IEqualityComparer_K: comp.VerifyEmitDiagnostics( // (7,13): error CS0656: Missing compiler required member 'System.Collections.Generic.Dictionary`2..ctor' // c = []; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[]").WithArguments("System.Collections.Generic.Dictionary`2", ".ctor").WithLocation(7, 13), // (8,13): error CS0656: Missing compiler required member 'System.Collections.Generic.Dictionary`2..ctor' // c = [with()]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[with()]").WithArguments("System.Collections.Generic.Dictionary`2", ".ctor").WithLocation(8, 13), // (9,13): error CS0656: Missing compiler required member 'System.Collections.Generic.Dictionary`2..ctor' // c = [with(i)]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[with(i)]").WithArguments("System.Collections.Generic.Dictionary`2", ".ctor").WithLocation(9, 13), // (9,13): error CS1501: No overload for method '<signature>' takes 1 arguments // c = [with(i)]; Diagnostic(ErrorCode.ERR_BadArgCount, "[with(i)]").WithArguments("<signature>", "1").WithLocation(9, 13), // (10,13): error CS0656: Missing compiler required member 'System.Collections.Generic.Dictionary`2..ctor' // c = [with(e)]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[with(e)]").WithArguments("System.Collections.Generic.Dictionary`2", ".ctor").WithLocation(10, 13), // (10,13): error CS1501: No overload for method '<signature>' takes 1 arguments // c = [with(e)]; Diagnostic(ErrorCode.ERR_BadArgCount, "[with(e)]").WithArguments("<signature>", "1").WithLocation(10, 13), // (11,13): error CS0656: Missing compiler required member 'System.Collections.Generic.Dictionary`2..ctor' // c = [with(i, e)]; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "[with(i, e)]").WithArguments("System.Collections.Generic.Dictionary`2", ".ctor").WithLocation(11, 13), // (11,13): error CS1501: No overload for method '<signature>' takes 2 arguments // c = [with(i, e)]; Diagnostic(ErrorCode.ERR_BadArgCount, "[with(i, e)]").WithArguments("<signature>", "2").WithLocation(11, 13)); break; default: comp.VerifyEmitDiagnostics( // (9,19): error CS1503: Argument 1: cannot convert from 'int' to 'System.Collections.Generic.IEqualityComparer<int>?' // c = [with(i)]; Diagnostic(ErrorCode.ERR_BadArgType, "i").WithArguments("1", "int", "System.Collections.Generic.IEqualityComparer<int>?").WithLocation(9, 19), // (11,13): error CS1501: No overload for method '<signature>' takes 2 arguments // c = [with(i, e)]; Diagnostic(ErrorCode.ERR_BadArgCount, "[with(i, e)]").WithArguments("<signature>", "2").WithLocation(11, 13)); break; } } } #endif [Theory] [CombinatorialData] public void List_KnownLength_List( [CombinatorialValues("", "with(), ", "with(3), ")] string argsPrefix) { string source = $$""" using System.Collections.Generic; class Program { static void Main() { Create(1, 2, 3).Report(); } static List<T> Create<T>(params T[] items) { return [{{argsPrefix}} ..items]; } } """; var verifier = CompileAndVerify( [source, s_collectionExtensions], targetFramework: TargetFramework.Net80, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("[1, 2, 3], ")); verifier.VerifyDiagnostics(); string expectedIL; switch (argsPrefix) { case "with(), ": expectedIL = """ { // Code size 15 (0xf) .maxstack 3 .locals init (T[] V_0) IL_0000: ldarg.0 IL_0001: stloc.0 IL_0002: newobj "System.Collections.Generic.List<T>..ctor()" IL_0007: dup IL_0008: ldloc.0 IL_0009: callvirt "void System.Collections.Generic.List<T>.AddRange(System.Collections.Generic.IEnumerable<T>)" IL_000e: ret } """; break; case "with(3), ": expectedIL = """ { // Code size 16 (0x10) .maxstack 3 .locals init (T[] V_0) IL_0000: ldarg.0 IL_0001: stloc.0 IL_0002: ldc.i4.3 IL_0003: newobj "System.Collections.Generic.List<T>..ctor(int)" IL_0008: dup IL_0009: ldloc.0 IL_000a: callvirt "void System.Collections.Generic.List<T>.AddRange(System.Collections.Generic.IEnumerable<T>)" IL_000f: ret } """; break; default: expectedIL = """ { // Code size 7 (0x7) .maxstack 1 IL_0000: ldarg.0 IL_0001: call "System.Collections.Generic.List<T> System.Linq.Enumerable.ToList<T>(System.Collections.Generic.IEnumerable<T>)" IL_0006: ret } """; break; } verifier.VerifyIL("Program.Create<T>", expectedIL); } [Fact] public void DefiniteAssignment_01() { string source = """ using System.Collections.Generic; class Program { static HashSet<T> Create<T>() { IEqualityComparer<T> e = null; return [with(e)]; } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics(); } [Fact] public void DefiniteAssignment_02() { string source = """ using System.Collections.Generic; class Program { static IEqualityComparer<T> Create<T>() { IEqualityComparer<T> e; HashSet<T> s = [with(e = null)]; return e; } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics(); } [Fact] public void NullableAnalysis_01() { string source = """ #nullable enable using System.Collections.Generic; class Program { static IEqualityComparer<T> Create<T>() { IEqualityComparer<T>? e = null; HashSet<T> s = [with(e = Create<T>())]; return e; } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics(); } [Fact] public void NullableAnalysis_02() { var source = """ #nullable enable using System.Collections.Generic; class Program { static IEqualityComparer<T> Create<T>() { IEqualityComparer<T>? e = null; HashSet<string> s = ["", with(e = Create<T>())]; return e; } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (8,34): error CS9400: 'with(...)' element must be the first element // HashSet<string> s = ["", with(e = Create<T>())]; Diagnostic(ErrorCode.ERR_CollectionArgumentsMustBeFirst, "with").WithLocation(8, 34)); } [Fact] public void NullableAnalysis_03() { var source = """ #nullable enable using System.Collections.Generic; class Program { static IEqualityComparer<T> Create<T>() { IEqualityComparer<T>? e = null; HashSet<string> s = [e.ToString(), with(e = Create<T>())]; return e; } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (8,30): warning CS8602: Dereference of a possibly null reference. // HashSet<string> s = [e.ToString(), with(e = Create<T>())]; Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "e").WithLocation(8, 30), // (8,44): error CS9400: 'with(...)' element must be the first element // HashSet<string> s = [e.ToString(), with(e = Create<T>())]; Diagnostic(ErrorCode.ERR_CollectionArgumentsMustBeFirst, "with").WithLocation(8, 44)); } [Fact] public void NullableAnalysis_04() { var source = """ #nullable enable using System.Collections.Generic; class Program { static IEqualityComparer<T> Create<T>() { IEqualityComparer<T>? e = Create<T>(); HashSet<string> s = [(e = null).ToString(), with((IEqualityComparer<string>)(object)e.ToString())]; return e; } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (8,31): warning CS8602: Dereference of a possibly null reference. // HashSet<string> s = [(e = null).ToString(), with((IEqualityComparer<string>)(object)e.ToString())]; Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "e = null").WithLocation(8, 31), // (8,53): error CS9400: 'with(...)' element must be the first element // HashSet<string> s = [(e = null).ToString(), with((IEqualityComparer<string>)(object)e.ToString())]; Diagnostic(ErrorCode.ERR_CollectionArgumentsMustBeFirst, "with").WithLocation(8, 53)); } [Fact] public void NullableAnalysis_05() { string source = """ #nullable enable using System.Collections.Generic; class Program { static IEqualityComparer<string> Create() { IEqualityComparer<string>? e = Create(); HashSet<string> s = [with((e = null)), e.ToString()]; return e; } } """; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (8,48): warning CS8602: Dereference of a possibly null reference. // HashSet<string> s = [with((e = null)), e.ToString()]; Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "e").WithLocation(8, 48)); } [Fact] public void ParamsCycle_ParamsConstructorOnly() { string sourceA = """ using System.Collections; using System.Collections.Generic; class MyCollection<T> : IEnumerable<T> { private readonly List<T> _list; IEnumerator<T> IEnumerable<T>.GetEnumerator() => _list.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => _list.GetEnumerator(); public MyCollection(params MyCollection<T> other) { _list = new(other); } public void Add(T t) { _list.Add(t); } } """; string sourceB = """ MyCollection<int> c; c = []; c = [with()]; c = [with(null)]; c = [with(1)]; """; var comp = CreateCompilation([sourceA, sourceB]); comp.VerifyEmitDiagnostics( // (2,5): error CS9223: Creation of params collection 'MyCollection<int>' results in an infinite chain of invocation of constructor 'MyCollection<T>.MyCollection(params MyCollection<T>)'. // c = []; Diagnostic(ErrorCode.ERR_ParamsCollectionInfiniteChainOfConstructorCalls, "[]").WithArguments("MyCollection<int>", "MyCollection<T>.MyCollection(params MyCollection<T>)").WithLocation(2, 5), // (3,6): error CS9223: Creation of params collection 'MyCollection<int>' results in an infinite chain of invocation of constructor 'MyCollection<T>.MyCollection(params MyCollection<T>)'. // c = [with()]; Diagnostic(ErrorCode.ERR_ParamsCollectionInfiniteChainOfConstructorCalls, "with()").WithArguments("MyCollection<int>", "MyCollection<T>.MyCollection(params MyCollection<T>)").WithLocation(3, 6), // (5,6): error CS9223: Creation of params collection 'MyCollection<int>' results in an infinite chain of invocation of constructor 'MyCollection<T>.MyCollection(params MyCollection<T>)'. // c = [with(1)]; Diagnostic(ErrorCode.ERR_ParamsCollectionInfiniteChainOfConstructorCalls, "with(1)").WithArguments("MyCollection<int>", "MyCollection<T>.MyCollection(params MyCollection<T>)").WithLocation(5, 6)); } [Fact] [WorkItem("https://github.com/dotnet/roslyn/issues/77784")] public void ParamsCycle_MultipleConstructors() { string sourceA = """ using System.Collections; using System.Collections.Generic; class MyCollection<T> : IEnumerable<T> { private readonly List<T> _list; IEnumerator<T> IEnumerable<T>.GetEnumerator() => _list.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => _list.GetEnumerator(); public MyCollection() { _list = new(); } public MyCollection(params MyCollection<T> other) { _list = new(other); } public void Add(T t) { _list.Add(t); } } """; string sourceB = """ MyCollection<int> c; c = []; c = [with()]; c = [with(null)]; c = [with(1)]; """; var comp = CreateCompilation([sourceA, sourceB]); comp.VerifyEmitDiagnostics(); } [Fact] [WorkItem("https://github.com/dotnet/roslyn/issues/77784")] public void ParamsCycle_MultipleConstructors_ClassContext() { string source = """ using System; using System.Collections; using System.Collections.Generic; class MyCollection<T> : IEnumerable<T> { private readonly List<T> _list; IEnumerator<T> IEnumerable<T>.GetEnumerator() => _list.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => _list.GetEnumerator(); public MyCollection() { _list = new(); } public MyCollection(params MyCollection<T> other) { _list = new(other); } public void Add(T t) { _list.Add(t); } } class C { static void Main() { MyCollection<int> c = [with(1)]; foreach (var item in c) Console.Write(item); } } """; CompileAndVerify(source, options: TestOptions.ReleaseExe, expectedOutput: "1").VerifyDiagnostics(); } [Fact] public void ParamsCycle_PrivateParameterlessConstructor() { string sourceA = """ using System.Collections; using System.Collections.Generic; class MyCollection<T> : IEnumerable<T> { private readonly List<T> _list; IEnumerator<T> IEnumerable<T>.GetEnumerator() => _list.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => _list.GetEnumerator(); private MyCollection() { } public MyCollection(params MyCollection<T> other) { _list = new(other); } public void Add(T t) { _list.Add(t); } } """; string sourceB = """ MyCollection<int> c; c = []; c = [with()]; c = [with(null)]; c = [with(1)]; """; var comp = CreateCompilation([sourceA, sourceB]); comp.VerifyEmitDiagnostics( // (2,5): error CS9223: Creation of params collection 'MyCollection<int>' results in an infinite chain of invocation of constructor 'MyCollection<T>.MyCollection(params MyCollection<T>)'. // c = []; Diagnostic(ErrorCode.ERR_ParamsCollectionInfiniteChainOfConstructorCalls, "[]").WithArguments("MyCollection<int>", "MyCollection<T>.MyCollection(params MyCollection<T>)").WithLocation(2, 5), // (3,6): error CS9223: Creation of params collection 'MyCollection<int>' results in an infinite chain of invocation of constructor 'MyCollection<T>.MyCollection(params MyCollection<T>)'. // c = [with()]; Diagnostic(ErrorCode.ERR_ParamsCollectionInfiniteChainOfConstructorCalls, "with()").WithArguments("MyCollection<int>", "MyCollection<T>.MyCollection(params MyCollection<T>)").WithLocation(3, 6), // (5,6): error CS9223: Creation of params collection 'MyCollection<int>' results in an infinite chain of invocation of constructor 'MyCollection<T>.MyCollection(params MyCollection<T>)'. // c = [with(1)]; Diagnostic(ErrorCode.ERR_ParamsCollectionInfiniteChainOfConstructorCalls, "with(1)").WithArguments("MyCollection<int>", "MyCollection<T>.MyCollection(params MyCollection<T>)").WithLocation(5, 6), // (9,25): error CS9224: Method 'MyCollection<T>.MyCollection()' cannot be less visible than the member with params collection 'MyCollection<T>.MyCollection(params MyCollection<T>)'. // public MyCollection(params MyCollection<T> other) { _list = new(other); } Diagnostic(ErrorCode.ERR_ParamsMemberCannotBeLessVisibleThanDeclaringMember, "params MyCollection<T> other").WithArguments("MyCollection<T>.MyCollection()", "MyCollection<T>.MyCollection(params MyCollection<T>)").WithLocation(9, 25)); } [Fact] public void ParamsCycle_NoParameterlessConstructor() { string sourceA = """ using System.Collections; using System.Collections.Generic; class MyCollection<T> : IEnumerable<T> { private readonly List<T> _list; IEnumerator<T> IEnumerable<T>.GetEnumerator() => _list.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => _list.GetEnumerator(); public MyCollection(T x, params MyCollection<T> y) { _list = new(); _list.Add(x); _list.AddRange(y); } public void Add(T t) { _list.Add(t); } } """; string sourceB = """ MyCollection<int> c; c = []; c = [with()]; c = [with(1)]; """; var comp = CreateCompilation([sourceA, sourceB]); comp.VerifyEmitDiagnostics( // (2,5): error CS9214: Collection expression type must have an applicable constructor that can be called with no arguments. // c = []; Diagnostic(ErrorCode.ERR_CollectionExpressionMissingConstructor, "[]").WithLocation(2, 5), // (3,6): error CS7036: There is no argument given that corresponds to the required parameter 'x' of 'MyCollection<int>.MyCollection(int, params MyCollection<int>)' // c = [with()]; Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "with()").WithArguments("x", "MyCollection<int>.MyCollection(int, params MyCollection<int>)").WithLocation(3, 6), // (4,6): error CS7036: There is no argument given that corresponds to the required parameter 'y' of 'MyCollection<int>.MyCollection(int, params MyCollection<int>)' // c = [with(1)]; Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "with(1)").WithArguments("y", "MyCollection<int>.MyCollection(int, params MyCollection<int>)").WithLocation(4, 6), // (8,30): error CS9228: Non-array params collection type must have an applicable constructor that can be called with no arguments. // public MyCollection(T x, params MyCollection<T> y) Diagnostic(ErrorCode.ERR_ParamsCollectionMissingConstructor, "params MyCollection<T> y").WithLocation(8, 30)); } [Fact] public void CollectionBuilderOverloadResolutionPriority() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyCollection<T> : IEnumerable<T> { public MyCollection(ReadOnlySpan<T> items) { } IEnumerator<T> IEnumerable<T>.GetEnumerator() => throw null; IEnumerator IEnumerable.GetEnumerator() => throw null; } class MyBuilder { public static MyCollection<T> Create<T>(string s, object o, ReadOnlySpan<T> items) { Console.WriteLine("Called first overload"); return new(items); } [OverloadResolutionPriority(1)] public static MyCollection<T> Create<T>(object o, string s, ReadOnlySpan<T> items) { Console.WriteLine("Called second overload"); return new(items); } } """; string sourceB = """ using System; class Program { static void Main() { MyCollection<string> c = [with("", ""), ""]; } } """; var comp = CompileAndVerify( [sourceA, sourceB, OverloadResolutionPriorityAttributeDefinition], targetFramework: TargetFramework.Net80, expectedOutput: IncludeExpectedOutput( """ Called second overload """), verify: Verification.FailsPEVerify).VerifyIL("Program.Main", """ { // Code size 30 (0x1e) .maxstack 3 .locals init (string V_0) IL_0000: ldstr "" IL_0005: ldstr "" IL_000a: ldstr "" IL_000f: stloc.0 IL_0010: ldloca.s V_0 IL_0012: newobj "System.ReadOnlySpan<string>..ctor(ref readonly string)" IL_0017: call "MyCollection<string> MyBuilder.Create<string>(object, string, System.ReadOnlySpan<string>)" IL_001c: pop IL_001d: ret } """); } [Fact] public void CollectionBuilderNoOverloadResolutionPriority() { string sourceA = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyCollection<T> : IEnumerable<T> { public MyCollection(ReadOnlySpan<T> items) { } IEnumerator<T> IEnumerable<T>.GetEnumerator() => throw null; IEnumerator IEnumerable.GetEnumerator() => throw null; } class MyBuilder { public static MyCollection<T> Create<T>(string s, object o, ReadOnlySpan<T> items) { return new(items); } public static MyCollection<T> Create<T>(object o, string s, ReadOnlySpan<T> items) { return new(items); } } """; string sourceB = """ class Program { static void Main() { MyCollection<string> c = [with("", ""), ""]; } } """; var comp = CreateCompilation( [sourceA, sourceB], targetFramework: TargetFramework.Net80).VerifyDiagnostics( // (5,35): error CS0121: The call is ambiguous between the following methods or properties: 'MyBuilder.Create<string>(string, object, ReadOnlySpan<string>)' and 'MyBuilder.Create<string>(object, string, ReadOnlySpan<string>)' // MyCollection<string> c = [with("", ""), ""]; Diagnostic(ErrorCode.ERR_AmbigCall, @"with("""", """")").WithArguments("MyBuilder.Create<string>(string, object, System.ReadOnlySpan<string>)", "MyBuilder.Create<string>(object, string, System.ReadOnlySpan<string>)")); } [Fact] public void InterpolatedStringHandler_Constructor() { var code = """ using System; using System.Runtime.CompilerServices; using System.Collections.Generic; public class C : List<int> { public C(int i, string s, [InterpolatedStringHandlerArgumentAttribute("i", "s")] CustomHandler c) => Console.WriteLine(c.ToString()); } public partial struct CustomHandler { public CustomHandler(int literalLength, int formattedCount, int i, string s) : this(literalLength, formattedCount) { _builder.AppendLine("i:" + i.ToString()); _builder.AppendLine("s:" + s); } } """; var executableCode = """ class Program { static void Main() { int i = 10; string s = "arg"; C c = [with(i, s, $"" + $"literal")]; } } """; var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: true); CompileAndVerify([code, executableCode, InterpolatedStringHandlerArgumentAttribute, handler], expectedOutput: """ i:10 s:arg literal:literal """) .VerifyDiagnostics() .VerifyIL("Program.Main", """ { // Code size 45 (0x2d) .maxstack 7 .locals init (string V_0, //s int V_1, string V_2, CustomHandler V_3) IL_0000: ldc.i4.s 10 IL_0002: ldstr "arg" IL_0007: stloc.0 IL_0008: stloc.1 IL_0009: ldloc.1 IL_000a: ldloc.0 IL_000b: stloc.2 IL_000c: ldloc.2 IL_000d: ldloca.s V_3 IL_000f: ldc.i4.7 IL_0010: ldc.i4.0 IL_0011: ldloc.1 IL_0012: ldloc.2 IL_0013: call "CustomHandler..ctor(int, int, int, string)" IL_0018: ldloca.s V_3 IL_001a: ldstr "literal" IL_001f: call "bool CustomHandler.AppendLiteral(string)" IL_0024: pop IL_0025: ldloc.3 IL_0026: newobj "C..ctor(int, string, CustomHandler)" IL_002b: pop IL_002c: ret } """); } [Fact] public void InterpolatedStringHandler_CollectionBuilder() { var code = """ using System; using System.Runtime.CompilerServices; using System.Collections.Generic; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyCollection<T> : List<T> { public MyCollection( int i, string s, CustomHandler c, ReadOnlySpan<T> items) { Console.WriteLine(c); foreach (var item in items) this.Add(item); } } class MyBuilder { public static MyCollection<T> Create<T>(int i, string s, [InterpolatedStringHandlerArgumentAttribute("i", "s")] CustomHandler c, ReadOnlySpan<T> items) => new(i, s, c, items); } public partial struct CustomHandler { public CustomHandler(int literalLength, int formattedCount, int i, string s) : this(literalLength, formattedCount) { _builder.AppendLine("i:" + i.ToString()); _builder.AppendLine("s:" + s); } } """; var executableCode = """ class Program { static void Main() { int i = 10; string s = "arg"; MyCollection<string> c = [with(i, s, $"" + $"literal"), "goo"]; } } """; var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: true); CompileAndVerify( [code, executableCode, handler], targetFramework: TargetFramework.Net90, verify: Verification.FailsPEVerify, expectedOutput: IncludeExpectedOutput(""" i:10 s:arg literal:literal """)) .VerifyDiagnostics( // (4,34): warning CS0436: The type 'InterpolatedStringHandlerAttribute' in '' conflicts with the imported type 'InterpolatedStringHandlerAttribute' in 'System.Runtime, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. Using the type defined in ''. // [System.Runtime.CompilerServices.InterpolatedStringHandler] Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "InterpolatedStringHandler").WithArguments("", "System.Runtime.CompilerServices.InterpolatedStringHandlerAttribute", "System.Runtime, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", "System.Runtime.CompilerServices.InterpolatedStringHandlerAttribute").WithLocation(4, 34)) .VerifyIL("Program.Main", """ { // Code size 59 (0x3b) .maxstack 7 .locals init (string V_0, //s string V_1, int V_2, string V_3, CustomHandler V_4) IL_0000: ldc.i4.s 10 IL_0002: ldstr "arg" IL_0007: stloc.0 IL_0008: stloc.2 IL_0009: ldloc.2 IL_000a: ldloc.0 IL_000b: stloc.3 IL_000c: ldloc.3 IL_000d: ldloca.s V_4 IL_000f: ldc.i4.7 IL_0010: ldc.i4.0 IL_0011: ldloc.2 IL_0012: ldloc.3 IL_0013: call "CustomHandler..ctor(int, int, int, string)" IL_0018: ldloca.s V_4 IL_001a: ldstr "literal" IL_001f: call "bool CustomHandler.AppendLiteral(string)" IL_0024: pop IL_0025: ldloc.s V_4 IL_0027: ldstr "goo" IL_002c: stloc.1 IL_002d: ldloca.s V_1 IL_002f: newobj "System.ReadOnlySpan<string>..ctor(ref readonly string)" IL_0034: call "MyCollection<string> MyBuilder.Create<string>(int, string, CustomHandler, System.ReadOnlySpan<string>)" IL_0039: pop IL_003a: ret } """); } [Fact] public void WithOutsideCollectionIsAnInvocation() { var source = """ using System.Collections.Generic; class C { void M() { N(with(capacity: 0), 1, 2, 3); } void N(params List<int> list) { } } """; CreateCompilation(source).VerifyDiagnostics( // (6,11): error CS0103: The name 'with' does not exist in the current context // N(with(capacity: 0), 1, 2, 3); Diagnostic(ErrorCode.ERR_NameNotInContext, "with").WithArguments("with").WithLocation(6, 11)); } [Theory] [InlineData("object")] [InlineData("dynamic")] public void WithElement_CollectionBuilder_DynamicArguments(string parameterType) { var source = $$""" using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyCollection<T> : IEnumerable<T> { public {{parameterType}} Value; private readonly List<T> _items; public MyCollection({{parameterType}} value, ReadOnlySpan<T> items) { Value = value; _items = new(); _items.AddRange(items.ToArray()); } public IEnumerator<T> GetEnumerator() => _items.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } class MyBuilder { public static MyCollection<T> Create<T>({{parameterType}} value, ReadOnlySpan<T> items) => new(value, items); } class C { static void Main() { dynamic d = 42; MyCollection<int> list = [with(d), 1]; Console.WriteLine(list.Value); } } """; if (parameterType == "dynamic") { CreateCompilation(source, targetFramework: TargetFramework.Net100).VerifyDiagnostics( // (23,97): error CS1978: Cannot use an expression of type 'ReadOnlySpan<T>' as an argument to a dynamically dispatched operation. // public static MyCollection<T> Create<T>(dynamic value, ReadOnlySpan<T> items) => new(value, items); Diagnostic(ErrorCode.ERR_BadDynamicMethodArg, "items").WithArguments("System.ReadOnlySpan<T>").WithLocation(23, 97), // (31,40): error CS9402: 'with(...)' element arguments cannot be dynamic // MyCollection<int> list = [with(d), 1]; Diagnostic(ErrorCode.ERR_CollectionArgumentsDynamicBinding, "d").WithLocation(31, 40)); } else { CreateCompilation(source, targetFramework: TargetFramework.Net100).VerifyDiagnostics( // (31,40): error CS9402: 'with(...)' element arguments cannot be dynamic // MyCollection<int> list = [with(d), 1]; Diagnostic(ErrorCode.ERR_CollectionArgumentsDynamicBinding, "d").WithLocation(31, 40)); } } [Theory] [InlineData("object")] [InlineData("dynamic")] public void WithElement_CollectionBuilder_DynamicParameters(string argumentType) { var source = $$""" using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyCollection<T> : IEnumerable<T> { public object Value; private readonly List<T> _items; public MyCollection(object value, ReadOnlySpan<T> items) { Value = value; _items = new(); _items.AddRange(items.ToArray()); } public IEnumerator<T> GetEnumerator() => _items.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } class MyBuilder { public static MyCollection<T> Create<T>(object value, ReadOnlySpan<T> items) => new(value, items); } class C { static void Main() { {{argumentType}} d = 42; MyCollection<int> list = [with(d), 1]; Console.WriteLine(list.Value); } } """; if (argumentType == "dynamic") { CreateCompilation(source, targetFramework: TargetFramework.Net100).VerifyDiagnostics( // (31,40): error CS9402: 'with(...)' element arguments cannot be dynamic // MyCollection<int> list = [with(d), 1]; Diagnostic(ErrorCode.ERR_CollectionArgumentsDynamicBinding, "d").WithLocation(31, 40)); } else { CompileAndVerify(source, targetFramework: TargetFramework.Net100, verify: Verification.FailsPEVerify).VerifyIL("C.Main", """ { // Code size 33 (0x21) .maxstack 2 IL_0000: ldc.i4.s 42 IL_0002: box "int" IL_0007: ldtoken "<PrivateImplementationDetails>.__StaticArrayInitTypeSize=4_Align=4 <PrivateImplementationDetails>.67ABDD721024F0FF4E0B3F4C2FC13BC5BAD42D0B7851D456D88D203D15AAA4504" IL_000c: call "System.ReadOnlySpan<int> System.Runtime.CompilerServices.RuntimeHelpers.CreateSpan<int>(System.RuntimeFieldHandle)" IL_0011: call "MyCollection<int> MyBuilder.Create<int>(object, System.ReadOnlySpan<int>)" IL_0016: ldfld "object MyCollection<int>.Value" IL_001b: call "void System.Console.WriteLine(object)" IL_0020: ret } """); } } [Fact] public void WithElement_CollectionBuilder_ArgList() { var source = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyCollection<T> : List<T> { public MyCollection(__arglist, ReadOnlySpan<T> items) : base(span.ToArray()) { } } class MyBuilder { public static MyCollection<T> Create<T>(__arglist, ReadOnlySpan<T> items) => new(__arglist, items); } """; CreateCompilation(source, targetFramework: TargetFramework.Net100).VerifyEmitDiagnostics( // (9,12): error CS0224: A method with vararg cannot be generic, be in a generic type, or have a params parameter // public MyCollection(__arglist, ReadOnlySpan<T> items) : base(span.ToArray()) Diagnostic(ErrorCode.ERR_BadVarargs, "MyCollection").WithLocation(9, 12), // (9,25): error CS0257: An __arglist parameter must be the last parameter in a parameter list // public MyCollection(__arglist, ReadOnlySpan<T> items) : base(span.ToArray()) Diagnostic(ErrorCode.ERR_VarargsLast, "__arglist").WithLocation(9, 25), // (9,66): error CS0103: The name 'span' does not exist in the current context // public MyCollection(__arglist, ReadOnlySpan<T> items) : base(span.ToArray()) Diagnostic(ErrorCode.ERR_NameNotInContext, "span").WithArguments("span").WithLocation(9, 66), // (16,35): error CS0224: A method with vararg cannot be generic, be in a generic type, or have a params parameter // public static MyCollection<T> Create<T>(__arglist, ReadOnlySpan<T> items) => new(__arglist, items); Diagnostic(ErrorCode.ERR_BadVarargs, "Create").WithLocation(16, 35), // (16,45): error CS0257: An __arglist parameter must be the last parameter in a parameter list // public static MyCollection<T> Create<T>(__arglist, ReadOnlySpan<T> items) => new(__arglist, items); Diagnostic(ErrorCode.ERR_VarargsLast, "__arglist").WithLocation(16, 45), // (16,86): error CS1503: Argument 1: cannot convert from 'System.RuntimeArgumentHandle' to 'System.ReadOnlySpan<T>' // public static MyCollection<T> Create<T>(__arglist, ReadOnlySpan<T> items) => new(__arglist, items); Diagnostic(ErrorCode.ERR_BadArgType, "__arglist").WithArguments("1", "System.RuntimeArgumentHandle", "System.ReadOnlySpan<T>").WithLocation(16, 86), // (16,97): error CS1503: Argument 2: cannot convert from 'ReadOnlySpan<T>' to '__arglist' // public static MyCollection<T> Create<T>(__arglist, ReadOnlySpan<T> items) => new(__arglist, items); Diagnostic(ErrorCode.ERR_BadArgType, "items").WithArguments("2", "System.ReadOnlySpan<T>", "__arglist").WithLocation(16, 97)); } [Fact] public void WithElement_CollectionBuilder_OverloadResolution_ExactMatch() { var source = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyList<T> : List<T> { public string ConstructorUsed { get; } public MyList(int capacity) : base(capacity) { ConstructorUsed = "int"; } public MyList(long capacity) : base((int)capacity) { ConstructorUsed = "long"; } } class MyBuilder { public static MyList<T> Create<T>(int capacity, ReadOnlySpan<T> items) => new(capacity); public static MyList<T> Create<T>(long capacity, ReadOnlySpan<T> items) => new(capacity); } class C { static void Main() { MyList<int> list1 = [with(10), 1]; MyList<int> list2 = [with(10L), 2]; Console.WriteLine($"{list1.ConstructorUsed},{list2.ConstructorUsed}"); } } """; CompileAndVerify(source, targetFramework: TargetFramework.Net100, expectedOutput: IncludeExpectedOutput("int,long"), verify: Verification.FailsPEVerify); } [Fact] public void WithElement_CollectionBuilder_OverloadResolution_Ambiguous() { var source = """ using System; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyList<T> : List<T> { public MyList(object value1, string value2) { Console.WriteLine("object/string chosen"); } public MyList(string value1, object value2) { Console.WriteLine("string/object chosen"); } } class MyBuilder { public static MyList<T> Create<T>(object value1, string value2, ReadOnlySpan<T> items) => new(value1, value2); public static MyList<T> Create<T>(string value1, object value2, ReadOnlySpan<T> items) => new(value1, value2); } class C { static void Main() { MyList<int> list = [with("", "")]; } } """; CreateCompilation(source, targetFramework: TargetFramework.Net100).VerifyDiagnostics( // (29,29): error CS0121: The call is ambiguous between the following methods or properties: 'MyBuilder.Create<int>(object, string, System.ReadOnlySpan<int>)' and 'MyBuilder.Create<int>(string, object, System.ReadOnlySpan<int>)' // MyList<int> list = [with("", "")]; Diagnostic(ErrorCode.ERR_AmbigCall, @"with("""", """")").WithArguments("MyBuilder.Create<int>(object, string, System.ReadOnlySpan<int>)", "MyBuilder.Create<int>(string, object, System.ReadOnlySpan<int>)").WithLocation(29, 29)); } [Fact] public void WithElement_CollectionBuilder_OverloadResolution_BestMatch1() { var source = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyList<T> : List<T> { public MyList(int capacity) : base(capacity) { Console.WriteLine("int chosen"); } public MyList(long capacity) : base((int)capacity) { Console.WriteLine("long chosen"); } } class MyBuilder { public static MyList<T> Create<T>(int capacity, ReadOnlySpan<T> items) => new(capacity); public static MyList<T> Create<T>(long capacity, ReadOnlySpan<T> items) => new(capacity); } class C { static void Main() { short s = 10; MyList<int> list = [with(s)]; } } """; CompileAndVerify(source, targetFramework: TargetFramework.Net100, expectedOutput: IncludeExpectedOutput("int chosen"), verify: Verification.FailsPEVerify); } [Fact] public void WithElement_CollectionBuilder_OverloadResolution_BestMatch2() { var source = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyList<T> : List<T> { public string ConstructorUsed { get; } public MyList(object value) : base() { ConstructorUsed = "object"; } public MyList(int value) : base() { ConstructorUsed = "int"; } } class MyBuilder { public static MyList<T> Create<T>(int capacity, ReadOnlySpan<T> items) => new(capacity); public static MyList<T> Create<T>(long capacity, ReadOnlySpan<T> items) => new(capacity); } class C { static void Main() { MyList<int> list = [with(42), 1]; Console.WriteLine(list.ConstructorUsed); } } """; CompileAndVerify(source, targetFramework: TargetFramework.Net100, expectedOutput: IncludeExpectedOutput("int"), verify: Verification.FailsPEVerify); } [Fact] public void WithElement_CollectionBuilder_NoMatchingConstructor() { var source = """ using System; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyList<T> : List<T> { public MyList(string value) : base() { } } class MyBuilder { public static MyList<T> Create<T>(string value, ReadOnlySpan<T> items) => new(value); } class C { void M() { MyList<int> list = [with(42)]; } } """; CreateCompilation(source, targetFramework: TargetFramework.Net100).VerifyDiagnostics( // (20,34): error CS1503: Argument 1: cannot convert from 'int' to 'string' // MyList<int> list = [with(42)]; Diagnostic(ErrorCode.ERR_BadArgType, "42").WithArguments("1", "int", "string").WithLocation(20, 34)); } [Fact] public void WithElement_CollectionBuilder_UserDefinedConversion1() { var source = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyList<T> : List<T> { public MyList(string value) : base() { } } class MyBuilder { public static MyList<T> Create<T>(string value, ReadOnlySpan<T> items) { Console.WriteLine("Factory called: " + value); return new(value); } } class C { static void Main() { MyList<int> list = [with(new C())]; } public static implicit operator string(C c) { Console.WriteLine("Implicit operator called"); return "converted"; } } """; CompileAndVerify( source, targetFramework: TargetFramework.Net100, verify: Verification.FailsPEVerify, expectedOutput: IncludeExpectedOutput(""" Implicit operator called Factory called: converted """)).VerifyIL("C.Main", """ { // Code size 26 (0x1a) .maxstack 2 .locals init (System.ReadOnlySpan<int> V_0) IL_0000: newobj "C..ctor()" IL_0005: call "string C.op_Implicit(C)" IL_000a: ldloca.s V_0 IL_000c: initobj "System.ReadOnlySpan<int>" IL_0012: ldloc.0 IL_0013: call "MyList<int> MyBuilder.Create<int>(string, System.ReadOnlySpan<int>)" IL_0018: pop IL_0019: ret } """); } [Fact] public void WithElement_CollectionBuilder_Constructor_UserDefinedConversion2() { var source = """ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyList<T> : List<T> { public MyList(long value) : base() { } } class MyBuilder { public static MyList<T> Create<T>(long value, ReadOnlySpan<T> items) => new(value); } class C { static void Main() { MyList<int> list = [with(new C())]; } public static implicit operator int(C c) { Console.WriteLine("conversion called"); return 0; } } """; CompileAndVerify( source, targetFramework: TargetFramework.Net100, verify: Verification.FailsPEVerify, expectedOutput: IncludeExpectedOutput(""" conversion called """)).VerifyIL("C.Main", """ { // Code size 27 (0x1b) .maxstack 2 .locals init (System.ReadOnlySpan<int> V_0) IL_0000: newobj "C..ctor()" IL_0005: call "int C.op_Implicit(C)" IL_000a: conv.i8 IL_000b: ldloca.s V_0 IL_000d: initobj "System.ReadOnlySpan<int>" IL_0013: ldloc.0 IL_0014: call "MyList<int> MyBuilder.Create<int>(long, System.ReadOnlySpan<int>)" IL_0019: pop IL_001a: ret } """); } [Fact] public void WithElement_CollectionBuilder_UnscopedRef1() { var source = """ using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class C<T> : List<T> { public C(out Span<string> egress, [UnscopedRef] out string ingress) { ingress = "a"; egress = new Span<string>(ref ingress); } Span<string> M() { string y = "a"; C<T> list = [with(out Span<string> x, out y)]; return x; } Span<string> N() { string y = "a"; C<T> list = new(out Span<string> x, out y); return x; } } class MyBuilder { public static C<T> Create<T>(out Span<string> egress, [UnscopedRef] out string ingress, ReadOnlySpan<T> items) => new(out egress, out ingress); } """; CreateCompilation(source, targetFramework: TargetFramework.Net100).VerifyDiagnostics( // (19,16): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope // return x; Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(19, 16), // (26,16): error CS8352: Cannot use variable 'x' in this context because it may expose referenced variables outside of their declaration scope // return x; Diagnostic(ErrorCode.ERR_EscapeVariable, "x").WithArguments("x").WithLocation(26, 16)); } [Fact] public void WithElement_CollectionBuilder_NotUnscopedRef1() { var source = """ using System; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class C<T> : List<T> { public C(out Span<string> egress, out string ingress) { ingress = "a"; egress = []; } Span<string> M() { string y = "a"; C<T> list = [with(out Span<string> x, out y)]; return x; } Span<string> N() { string y = "a"; C<T> list = new(out Span<string> x, out y); return x; } } class MyBuilder { public static C<T> Create<T>(out Span<string> egress, out string ingress, ReadOnlySpan<T> items) => new(out egress, out ingress); } """; CreateCompilation(source, targetFramework: TargetFramework.Net100).VerifyDiagnostics(); } [Fact] public void CollectionBuilder_GetMemberGroup() { string sourceA = """ using System; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyCollection<T> : List<T> { public MyCollection() { } } class MyBuilder { public static MyCollection<T> Create<T>(int i, ReadOnlySpan<T> items) => new(); public static MyCollection<T> Create<T>(string s, ReadOnlySpan<T> items) => new(); } """; string sourceB = """ class Program { static void Main() { MyCollection<string> c = [with(""), ""]; } } """; var comp = CreateCompilation( [sourceA, sourceB], targetFramework: TargetFramework.Net80).VerifyDiagnostics(); var syntaxTree = comp.SyntaxTrees[1]; var semanticModel = comp.GetSemanticModel(syntaxTree); var root = syntaxTree.GetRoot(); var withElement = root.DescendantNodes().OfType<WithElementSyntax>().Single(); // It is expected that we get 0 here. GetMemberGroup returns nothing for a WithElementSyntax // (same as for a ConstructorInitializerSyntax). var memberGroup = semanticModel.GetMemberGroup(withElement); Assert.Equal(0, memberGroup.Length); } [Fact] public void CollectionBuilder_GetSpeculativeSymbolInfo() { string sourceA = """ using System; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] class MyCollection<T> : List<T> { public MyCollection() { } } class MyBuilder { public static MyCollection<T> Create<T>(int i, ReadOnlySpan<T> items) => new(); public static MyCollection<T> Create<T>(string s, ReadOnlySpan<T> items) => new(); } """; string sourceB = """ class Program { static void Main() { MyCollection<string> c = [with(""), ""]; } } """; var comp = CreateCompilation( [sourceA, sourceB], targetFramework: TargetFramework.Net80).VerifyDiagnostics(); var syntaxTree = comp.SyntaxTrees[1]; var semanticModel = comp.GetSemanticModel(syntaxTree); var root = syntaxTree.GetRoot(); var withElement = root.DescendantNodes().OfType<WithElementSyntax>().Single(); var symbolInfo = semanticModel.GetSpeculativeSymbolInfo(withElement.SpanStart, SyntaxFactory.WithElement(SyntaxFactory.ArgumentList(SyntaxFactory.SingletonSeparatedList( SyntaxFactory.Argument(SyntaxFactory.ParseExpression("1"))))), SpeculativeBindingOption.BindAsExpression); // For now, we do not support speculating on a different WithElement. Assert.Null(symbolInfo.Symbol); Assert.Empty(symbolInfo.CandidateSymbols); } [Fact] public void CollectionBuilderFileLocalType1() { string sourceA = """ #nullable enable using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] file class MyCollection<T> : IEnumerable<T> { private readonly List<T> _items; public MyCollection(string value, ReadOnlySpan<T> items) { _items = new(); _items.AddRange(items.ToArray()); } public IEnumerator<T> GetEnumerator() => _items.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } file class MyBuilder { public static MyCollection<T> Create<T>(string value, ReadOnlySpan<T> items) => new(value, items); } class Program { static void Main() { MyCollection<int> c = [with(""), 1, 2]; Console.WriteLine(string.Join(", ", c)); } } """; CompileAndVerify( sourceA, expectedOutput: IncludeExpectedOutput("1, 2"), targetFramework: TargetFramework.Net80, verify: Verification.FailsPEVerify).VerifyDiagnostics(); } [Fact] public void CollectionBuilderFileLocalType2() { string sourceA = """ #nullable enable using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; [CollectionBuilder(typeof(MyBuilder), "Create")] file class MyCollection<T> : IEnumerable<T> { private readonly List<T> _items; public MyCollection(Arg value, ReadOnlySpan<T> items) { _items = new(); _items.AddRange(items.ToArray()); } public IEnumerator<T> GetEnumerator() => _items.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } file class Arg {} file class MyBuilder { public static MyCollection<T> Create<T>(Arg value, ReadOnlySpan<T> items) => new(value, items); } class Program { static void Main() { MyCollection<int> c = [with(new Arg()), 1, 2]; Console.WriteLine(string.Join(", ", c)); } } """; CompileAndVerify( sourceA, expectedOutput: IncludeExpectedOutput("1, 2"), targetFramework: TargetFramework.Net80, verify: Verification.FailsPEVerify).VerifyDiagnostics(); } [Fact] public void ConstructibleTypeParameterNoArguments() { string sourceA = """ using System; using System.Collections.Generic; class Program { static void Main() { var v = M<List<int>>(1); Console.WriteLine(v[0]); } static T M<T>(int i) where T : IList<int>, new() { T t = [with(), i]; return t; } } """; CompileAndVerify( sourceA, expectedOutput: IncludeExpectedOutput("1"), targetFramework: TargetFramework.Net80, verify: Verification.FailsPEVerify).VerifyDiagnostics(); } [Fact] public void ConstructibleTypeParameterWithArgument1() { string sourceA = """ using System; using System.Collections.Generic; class Program { static void Main() { var v = M<List<int>>(1); Console.WriteLine(v[0]); } static T M<T>(int i) where T : IList<int>, new() { T t = [with(i)]; return t; } } """; CreateCompilation(sourceA, targetFramework: TargetFramework.Net80).VerifyDiagnostics( // (14,16): error CS0417: 'T': cannot provide arguments when creating an instance of a variable type // T t = [with(i)]; Diagnostic(ErrorCode.ERR_NewTyvarWithArgs, "with(i)").WithArguments("T").WithLocation(14, 16)); } [Fact] public void ConstructibleTypeParameterWithArgument2() { string sourceA = """ #nullable enable using System; using System.Collections.Generic; class Program { static void Main() { var v = M<List<int>>(1); Console.WriteLine(v[0]); } static T M<T>(int i) where T : IList<int>, new() { string? s; T t = [with(s = "")]; Console.WriteLine(s); Goo(s); return t; } static void Goo(string s) { } } """; CreateCompilation(sourceA, targetFramework: TargetFramework.Net80).VerifyDiagnostics( // (16,16): error CS0417: 'T': cannot provide arguments when creating an instance of a variable type // T t = [with(s = "")]; Diagnostic(ErrorCode.ERR_NewTyvarWithArgs, @"with(s = """")").WithArguments("T").WithLocation(16, 16)); } [Theory] [InlineData("IList<int>")] [InlineData("ICollection<int>")] public void InterfaceTypeWithArgument1(string type) { string sourceA = $$""" #nullable enable using System.Collections.Generic; class Program { static void Main() { string? s; {{type}} t = [with(s = "")]; Goo(s); } static void Goo(string s) { } } """; CreateCompilation(sourceA, targetFramework: TargetFramework.Net80).VerifyDiagnostics( // (9,36): error CS1503: Argument 1: cannot convert from 'string' to 'int' // ICollection<int> t = [with(s = "")]; Diagnostic(ErrorCode.ERR_BadArgType, @"s = """"").WithArguments("1", "string", "int")); } [Fact] public void TestAwait1() { string sourceA = $$""" using System; using System.Threading.Tasks; using System.Collections.Generic; class Program { static async Task Main() { List<int> s = [with(await GetValue(42)), await GetValue(0), await GetValue(1)]; Console.WriteLine(s.Capacity); Console.WriteLine(string.Join(", ", s)); } static Task<int> GetValue(int value) => Task.FromResult(value); } """; var compilation = CreateRuntimeAsyncCompilation(sourceA, TestOptions.ReleaseExe); CompileAndVerify(compilation, expectedOutput: ExecutionConditionUtil.IsCoreClr && RuntimeAsyncTestHelpers.IsRuntimeAsyncEnabled ? """ 42 0, 1 """ : null, verify: Verification.Fails with { ILVerifyMessage = "[Main]: Return value missing on the stack. { Offset = 0x53 }" }) .VerifyDiagnostics().VerifyIL("Program.Main", """ { // Code size 84 (0x54) .maxstack 3 .locals init (System.Collections.Generic.List<int> V_0, //s int V_1, int V_2) IL_0000: ldc.i4.s 42 IL_0002: call "System.Threading.Tasks.Task<int> Program.GetValue(int)" IL_0007: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)" IL_000c: newobj "System.Collections.Generic.List<int>..ctor(int)" IL_0011: dup IL_0012: ldc.i4.0 IL_0013: call "System.Threading.Tasks.Task<int> Program.GetValue(int)" IL_0018: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)" IL_001d: stloc.1 IL_001e: ldloc.1 IL_001f: callvirt "void System.Collections.Generic.List<int>.Add(int)" IL_0024: dup IL_0025: ldc.i4.1 IL_0026: call "System.Threading.Tasks.Task<int> Program.GetValue(int)" IL_002b: call "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)" IL_0030: stloc.2 IL_0031: ldloc.2 IL_0032: callvirt "void System.Collections.Generic.List<int>.Add(int)" IL_0037: stloc.0 IL_0038: ldloc.0 IL_0039: callvirt "int System.Collections.Generic.List<int>.Capacity.get" IL_003e: call "void System.Console.WriteLine(int)" IL_0043: ldstr ", " IL_0048: ldloc.0 IL_0049: call "string string.Join<int>(string, System.Collections.Generic.IEnumerable<int>)" IL_004e: call "void System.Console.WriteLine(string)" IL_0053: ret } """); } }