Skip to content

Commit

Permalink
Collection expressions: synthesized list types should implement IColl…
Browse files Browse the repository at this point in the history
…ection and IList (#70288)
  • Loading branch information
cston authored Oct 17, 2023
1 parent ec4e3b2 commit 8074cb4
Show file tree
Hide file tree
Showing 5 changed files with 720 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ internal sealed class SynthesizedReadOnlyListTypeSymbol : NamedTypeSymbol

private static readonly WellKnownType[] s_requiredWellKnownTypes = new[]
{
WellKnownType.System_Collections_Generic_List_T,
WellKnownType.System_Collections_ICollection,
WellKnownType.System_Collections_IList,
};

private static readonly SpecialMember[] s_requiredSpecialMembers = new[]
Expand All @@ -48,6 +49,20 @@ internal sealed class SynthesizedReadOnlyListTypeSymbol : NamedTypeSymbol

private static readonly WellKnownMember[] s_requiredWellKnownMembers = new[]
{
WellKnownMember.System_Collections_ICollection__Count,
WellKnownMember.System_Collections_ICollection__IsSynchronized,
WellKnownMember.System_Collections_ICollection__SyncRoot,
WellKnownMember.System_Collections_ICollection__CopyTo,
WellKnownMember.System_Collections_IList__get_Item,
WellKnownMember.System_Collections_IList__IsFixedSize,
WellKnownMember.System_Collections_IList__IsReadOnly,
WellKnownMember.System_Collections_IList__Add,
WellKnownMember.System_Collections_IList__Clear,
WellKnownMember.System_Collections_IList__Contains,
WellKnownMember.System_Collections_IList__IndexOf,
WellKnownMember.System_Collections_IList__Insert,
WellKnownMember.System_Collections_IList__Remove,
WellKnownMember.System_Collections_IList__RemoveAt,
WellKnownMember.System_Collections_Generic_IReadOnlyCollection_T__Count,
WellKnownMember.System_Collections_Generic_IReadOnlyList_T__get_Item,
WellKnownMember.System_Collections_Generic_ICollection_T__Count,
Expand Down Expand Up @@ -87,6 +102,18 @@ internal static NamedTypeSymbol Create(SourceModuleSymbol containingModule, stri
}
}

if (diagnosticInfo is null)
{
foreach (var type in s_requiredWellKnownTypes)
{
diagnosticInfo = compilation.GetWellKnownType(type).GetUseSiteInfo().DiagnosticInfo;
if (diagnosticInfo is { })
{
break;
}
}
}

if (diagnosticInfo is null)
{
foreach (var member in s_requiredSpecialMembers)
Expand Down Expand Up @@ -183,6 +210,8 @@ private SynthesizedReadOnlyListTypeSymbol(SourceModuleSymbol containingModule, s
_field = new SynthesizedFieldSymbol(this, fieldType, "_items", isReadOnly: true);

var iEnumerable = compilation.GetSpecialType(SpecialType.System_Collections_IEnumerable);
var iCollection = compilation.GetWellKnownType(WellKnownType.System_Collections_ICollection);
var iList = compilation.GetWellKnownType(WellKnownType.System_Collections_IList);
var iEnumerableT = compilation.GetSpecialType(SpecialType.System_Collections_Generic_IEnumerable_T).Construct(typeArgs);
var iReadOnlyCollectionT = compilation.GetSpecialType(SpecialType.System_Collections_Generic_IReadOnlyCollection_T).Construct(typeArgs);
var iReadOnlyListT = compilation.GetSpecialType(SpecialType.System_Collections_Generic_IReadOnlyList_T).Construct(typeArgs);
Expand All @@ -191,6 +220,8 @@ private SynthesizedReadOnlyListTypeSymbol(SourceModuleSymbol containingModule, s

_interfaces = ImmutableArray.Create(
iEnumerable,
iCollection,
iList,
iEnumerableT,
iReadOnlyCollectionT,
iReadOnlyListT,
Expand All @@ -207,6 +238,77 @@ private SynthesizedReadOnlyListTypeSymbol(SourceModuleSymbol containingModule, s
this,
(MethodSymbol)compilation.GetSpecialTypeMember(SpecialMember.System_Collections_IEnumerable__GetEnumerator),
generateGetEnumerator));
addProperty(membersBuilder,
new SynthesizedReadOnlyListProperty(
this,
(PropertySymbol)compilation.GetWellKnownTypeMember(WellKnownMember.System_Collections_ICollection__Count)!,
generateCount));
addProperty(membersBuilder,
new SynthesizedReadOnlyListProperty(
this,
(PropertySymbol)compilation.GetWellKnownTypeMember(WellKnownMember.System_Collections_ICollection__IsSynchronized)!,
generateIsSynchronized));
addProperty(membersBuilder,
new SynthesizedReadOnlyListProperty(
this,
(PropertySymbol)compilation.GetWellKnownTypeMember(WellKnownMember.System_Collections_ICollection__SyncRoot)!,
generateSyncRoot));
membersBuilder.Add(
new SynthesizedReadOnlyListMethod(
this,
(MethodSymbol)compilation.GetWellKnownTypeMember(WellKnownMember.System_Collections_ICollection__CopyTo)!,
generateCopyTo));
addProperty(membersBuilder,
new SynthesizedReadOnlyListProperty(
this,
(PropertySymbol)((MethodSymbol)compilation.GetWellKnownTypeMember(WellKnownMember.System_Collections_IList__get_Item)!).AssociatedSymbol,
generateIndexer,
generateNotSupportedException));
addProperty(membersBuilder,
new SynthesizedReadOnlyListProperty(
this,
(PropertySymbol)compilation.GetWellKnownTypeMember(WellKnownMember.System_Collections_IList__IsFixedSize)!,
generateIsFixedSize));
addProperty(membersBuilder,
new SynthesizedReadOnlyListProperty(
this,
(PropertySymbol)compilation.GetWellKnownTypeMember(WellKnownMember.System_Collections_IList__IsReadOnly)!,
generateIsReadOnly));
membersBuilder.Add(
new SynthesizedReadOnlyListMethod(
this,
(MethodSymbol)compilation.GetWellKnownTypeMember(WellKnownMember.System_Collections_IList__Add)!,
generateNotSupportedException));
membersBuilder.Add(
new SynthesizedReadOnlyListMethod(
this,
(MethodSymbol)compilation.GetWellKnownTypeMember(WellKnownMember.System_Collections_IList__Clear)!,
generateNotSupportedException));
membersBuilder.Add(
new SynthesizedReadOnlyListMethod(
this,
(MethodSymbol)compilation.GetWellKnownTypeMember(WellKnownMember.System_Collections_IList__Contains)!,
generateContains));
membersBuilder.Add(
new SynthesizedReadOnlyListMethod(
this,
(MethodSymbol)compilation.GetWellKnownTypeMember(WellKnownMember.System_Collections_IList__IndexOf)!,
generateIndexOf));
membersBuilder.Add(
new SynthesizedReadOnlyListMethod(
this,
(MethodSymbol)compilation.GetWellKnownTypeMember(WellKnownMember.System_Collections_IList__Insert)!,
generateNotSupportedException));
membersBuilder.Add(
new SynthesizedReadOnlyListMethod(
this,
(MethodSymbol)compilation.GetWellKnownTypeMember(WellKnownMember.System_Collections_IList__Remove)!,
generateNotSupportedException));
membersBuilder.Add(
new SynthesizedReadOnlyListMethod(
this,
(MethodSymbol)compilation.GetWellKnownTypeMember(WellKnownMember.System_Collections_IList__RemoveAt)!,
generateNotSupportedException));
membersBuilder.Add(
new SynthesizedReadOnlyListMethod(
this,
Expand Down Expand Up @@ -310,7 +412,7 @@ static BoundStatement generateGetEnumeratorT(SyntheticBoundNodeFactory f, Method
interfaceMethod));
}

// IReadOnlyCollection<T>.Count, ICollection<T>.Count
// ICollection.Count, IReadOnlyCollection<T>.Count, ICollection<T>.Count
static BoundStatement generateCount(SyntheticBoundNodeFactory f, MethodSymbol method, MethodSymbol interfaceMethod)
{
var containingType = (SynthesizedReadOnlyListTypeSymbol)method.ContainingType;
Expand All @@ -331,21 +433,45 @@ static BoundStatement generateCount(SyntheticBoundNodeFactory f, MethodSymbol me
}
}

// ICollection<T>.IsReadOnly
// ICollection.IsSynchronized
static BoundStatement generateIsSynchronized(SyntheticBoundNodeFactory f, MethodSymbol method, MethodSymbol interfaceMethod)
{
// return false;
return f.Return(f.Literal(false));
}

// ICollection.SyncRoot
static BoundStatement generateSyncRoot(SyntheticBoundNodeFactory f, MethodSymbol method, MethodSymbol interfaceMethod)
{
// return (object)this;
return f.Return(
f.Convert(
interfaceMethod.ReturnType,
f.This()));
}

// IList.IsFixedSize
static BoundStatement generateIsFixedSize(SyntheticBoundNodeFactory f, MethodSymbol method, MethodSymbol interfaceMethod)
{
// return true;
return f.Return(f.Literal(true));
}

// IList.IsReadOnly, ICollection<T>.IsReadOnly
static BoundStatement generateIsReadOnly(SyntheticBoundNodeFactory f, MethodSymbol method, MethodSymbol interfaceMethod)
{
// return true;
return f.Return(f.Literal(true));
}

// ICollection<T>.Contains(T)
// IList.Contains(object), ICollection<T>.Contains(T)
static BoundStatement generateContains(SyntheticBoundNodeFactory f, MethodSymbol method, MethodSymbol interfaceMethod)
{
var containingType = (SynthesizedReadOnlyListTypeSymbol)method.ContainingType;
var field = containingType._field;
var fieldReference = f.Field(f.This(), field);
var parameterReference = f.Parameter(method.Parameters[0]);
if (field.Type.IsArray())
if (!interfaceMethod.ContainingType.IsGenericType || field.Type.IsArray())
{
// return ((ICollection<T>)_items).Contains(param0);
return f.Return(
Expand All @@ -368,7 +494,7 @@ static BoundStatement generateContains(SyntheticBoundNodeFactory f, MethodSymbol
}
}

// ICollection<T>.CopyTo(T[], int)
// ICollection.CopyTo(Array, int), ICollection<T>.CopyTo(T[], int)
static BoundStatement generateCopyTo(SyntheticBoundNodeFactory f, MethodSymbol method, MethodSymbol interfaceMethod)
{
var containingType = (SynthesizedReadOnlyListTypeSymbol)method.ContainingType;
Expand All @@ -377,7 +503,7 @@ static BoundStatement generateCopyTo(SyntheticBoundNodeFactory f, MethodSymbol m
var parameterReference0 = f.Parameter(method.Parameters[0]);
var parameterReference1 = f.Parameter(method.Parameters[1]);
BoundStatement statement;
if (field.Type.IsArray())
if (!interfaceMethod.ContainingType.IsGenericType || field.Type.IsArray())
{
// ((ICollection<T>)_items).CopyTo(param0, param1);
statement = f.ExpressionStatement(
Expand All @@ -403,7 +529,7 @@ static BoundStatement generateCopyTo(SyntheticBoundNodeFactory f, MethodSymbol m
return f.Block(statement, f.Return());
}

// IReadOnlyList<T>.this[int], IList<T>.this[int]
// IList.this[int], IReadOnlyList<T>.this[int], IList<T>.this[int]
static BoundStatement generateIndexer(SyntheticBoundNodeFactory f, MethodSymbol method, MethodSymbol interfaceMethod)
{
var containingType = (SynthesizedReadOnlyListTypeSymbol)method.ContainingType;
Expand All @@ -425,14 +551,14 @@ static BoundStatement generateIndexer(SyntheticBoundNodeFactory f, MethodSymbol
}
}

// IList<T>.IndexOf(T)
// IList.IndexOf(object), IList<T>.IndexOf(T)
static BoundStatement generateIndexOf(SyntheticBoundNodeFactory f, MethodSymbol method, MethodSymbol interfaceMethod)
{
var containingType = (SynthesizedReadOnlyListTypeSymbol)method.ContainingType;
var field = containingType._field;
var fieldReference = f.Field(f.This(), field);
var parameterReference = f.Parameter(method.Parameters[0]);
if (field.Type.IsArray())
if (!interfaceMethod.ContainingType.IsGenericType || field.Type.IsArray())
{
// return ((IList<T>)_items).IndexOf(param0);
return f.Return(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17419,6 +17419,21 @@ class C
".ctor",
".ctor",
"System.Collections.IEnumerable.GetEnumerator",
"System.Collections.ICollection.get_Count",
"System.Collections.ICollection.get_IsSynchronized",
"System.Collections.ICollection.get_SyncRoot",
"System.Collections.ICollection.CopyTo",
"System.Collections.IList.get_Item",
"System.Collections.IList.set_Item",
"System.Collections.IList.get_IsFixedSize",
"System.Collections.IList.get_IsReadOnly",
"System.Collections.IList.Add",
"System.Collections.IList.Clear",
"System.Collections.IList.Contains",
"System.Collections.IList.IndexOf",
"System.Collections.IList.Insert",
"System.Collections.IList.Remove",
"System.Collections.IList.RemoveAt",
"System.Collections.Generic.IEnumerable<T>.GetEnumerator",
"System.Collections.Generic.IReadOnlyCollection<T>.get_Count",
"System.Collections.Generic.IReadOnlyList<T>.get_Item",
Expand Down Expand Up @@ -17455,6 +17470,21 @@ class C
"F",
".ctor",
"System.Collections.IEnumerable.GetEnumerator",
"System.Collections.ICollection.get_Count",
"System.Collections.ICollection.get_IsSynchronized",
"System.Collections.ICollection.get_SyncRoot",
"System.Collections.ICollection.CopyTo",
"System.Collections.IList.get_Item",
"System.Collections.IList.set_Item",
"System.Collections.IList.get_IsFixedSize",
"System.Collections.IList.get_IsReadOnly",
"System.Collections.IList.Add",
"System.Collections.IList.Clear",
"System.Collections.IList.Contains",
"System.Collections.IList.IndexOf",
"System.Collections.IList.Insert",
"System.Collections.IList.Remove",
"System.Collections.IList.RemoveAt",
"System.Collections.Generic.IEnumerable<T>.GetEnumerator",
"System.Collections.Generic.IReadOnlyCollection<T>.get_Count",
"System.Collections.Generic.IReadOnlyList<T>.get_Item",
Expand Down Expand Up @@ -17492,6 +17522,21 @@ class C
"F",
".ctor",
"System.Collections.IEnumerable.GetEnumerator",
"System.Collections.ICollection.get_Count",
"System.Collections.ICollection.get_IsSynchronized",
"System.Collections.ICollection.get_SyncRoot",
"System.Collections.ICollection.CopyTo",
"System.Collections.IList.get_Item",
"System.Collections.IList.set_Item",
"System.Collections.IList.get_IsFixedSize",
"System.Collections.IList.get_IsReadOnly",
"System.Collections.IList.Add",
"System.Collections.IList.Clear",
"System.Collections.IList.Contains",
"System.Collections.IList.IndexOf",
"System.Collections.IList.Insert",
"System.Collections.IList.Remove",
"System.Collections.IList.RemoveAt",
"System.Collections.Generic.IEnumerable<T>.GetEnumerator",
"System.Collections.Generic.IReadOnlyCollection<T>.get_Count",
"System.Collections.Generic.IReadOnlyList<T>.get_Item",
Expand Down
Loading

0 comments on commit 8074cb4

Please sign in to comment.