Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Collection expressions: require Add method callable with a single argument for class and struct types that do not use [CollectionBuilder] #72654

Merged
merged 19 commits into from
Mar 28, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Update repro tests
  • Loading branch information
cston committed Mar 27, 2024
commit d7811fce5385f03c78573c458165d1c20bc2a842
Original file line number Diff line number Diff line change
Expand Up @@ -34899,95 +34899,109 @@ static void Main()
""");
}

[WorkItem("https://github.com/dotnet/roslyn/issues/72098")]
[Fact]
public void AddMethod_System_Windows_Input_InputGestureCollection()
public void AddMethod_Derived_01()
{
string sourceA = """
string source = """
using System.Collections;
using System.Collections.Generic;
namespace System.Windows.Input

class Element { }

class ElementCollection : IEnumerable
{
public class InputGesture
{
}
public sealed class InputGestureCollection : IList
private readonly List<object> _list = new();
public IEnumerator GetEnumerator() => _list.GetEnumerator();
public void Add(Element element) { _list.Add(element); }
}

class Program
{
static void Main()
{
private readonly List<object> _list = new();
object IList.this[int index] { get => _list[index]; set => _list[index] = value; }
bool IList.IsFixedSize => false;
bool IList.IsReadOnly => false;
int ICollection.Count => _list.Count;
bool ICollection.IsSynchronized => false;
object ICollection.SyncRoot => this;
int IList.Add(object value) => ((IList)_list).Add(value);
void IList.Clear() { _list.Clear(); }
bool IList.Contains(object value) => _list.Contains(value);
void ICollection.CopyTo(Array array, int index) => ((IList)_list).CopyTo(array, index);
IEnumerator IEnumerable.GetEnumerator() => _list.GetEnumerator();
int IList.IndexOf(object value) => _list.IndexOf(value);
void IList.Insert(int index, object value) => _list.Insert(index, value);
void IList.Remove(object value) => _list.Remove(value);
void IList.RemoveAt(int index) => _list.RemoveAt(index);
public int Add(InputGesture value) => ((IList)_list).Add(value);
ElementCollection c = [new Element(), null];
c.Report();
}
}
""";
var comp = CreateCompilation(sourceA);
var refA = comp.EmitToImageReference();
CompileAndVerify([source, s_collectionExtensions], expectedOutput: "[Element, null], ");
}

[WorkItem("https://github.com/dotnet/roslyn/issues/72098")]
[Fact]
public void AddMethod_Derived_02()
{
string source = """
using System.Collections;
using System.Collections.Generic;

class Base { }
class Element : Base { }

class ElementCollection : IEnumerable<Base>
{
private readonly List<Base> _list = new();
public IEnumerator<Base> GetEnumerator() => _list.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public void Add(Element element) { _list.Add(element); }
}

string sourceB = """
using System.Windows.Input;
class Program
{
static void Main()
{
InputGestureCollection c = [new InputGesture(), null];
ElementCollection c = [new Element(), null];
c.Report();
}
}
""";
CompileAndVerify([sourceB, s_collectionExtensions], references: [refA], expectedOutput: "[System.Windows.Input.InputGesture, null], ");
CompileAndVerify([source, s_collectionExtensions], expectedOutput: "[Element, null], ");
}

[WorkItem("https://github.com/dotnet/roslyn/issues/71240")]
[Fact]
public void AddMethod_System_CommandLine_Command()
public void AddMethod_Derived_03()
{
string sourceA = """
using System.Collections;
using System.Collections.Generic;
namespace System.CommandLine

class Sample<T> : IEnumerable<object[]>
{
public class Symbol
{
}
public class Argument : Symbol
{
}
public class Command : Symbol, IEnumerable<Symbol>
private readonly List<object[]> _list = new();
IEnumerator<object[]> IEnumerable<object[]>.GetEnumerator() => _list.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => _list.GetEnumerator();
public void Add(T t) { if (t is object[] o) _list.Add(o); }
}
""";

string sourceB1 = """
class Program
{
static void Main()
{
private readonly List<Symbol> _symbols = new();
public IEnumerator<Symbol> GetEnumerator() => _symbols.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public void Add(Argument argument) { _symbols.Add(argument); }
public void Add(Command command) { _symbols.Add(command); }
Sample<string[]> s = [["a"], ["b"], ["c"]];
s.Report();
}
}
""";
var comp = CreateCompilation(sourceA);
var refA = comp.EmitToImageReference();
CompileAndVerify([sourceA, sourceB1, s_collectionExtensions], expectedOutput: "[[a], [b], [c]], ");

string sourceB = """
using System.CommandLine;
string sourceB2 = """
class Program
{
static void Main()
{
Command c = [new Argument(), new Command()];
c.Report();
Sample<string> s = ["a", null];
}
}
""";
CompileAndVerify([sourceB, s_collectionExtensions], references: [refA], expectedOutput: "[System.CommandLine.Argument, []], ");
var comp = CreateCompilation([sourceA, sourceB2]);
comp.VerifyEmitDiagnostics(
// (5,29): error CS0029: Cannot implicitly convert type 'string' to 'object[]'
// Sample<string> s = ["a", null];
Diagnostic(ErrorCode.ERR_NoImplicitConv, @"""a""").WithArguments("string", "object[]").WithLocation(5, 29));
}

[Fact]
Expand Down
Loading