-
Notifications
You must be signed in to change notification settings - Fork 4k
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
Optimize single spread of IEnumerable to array #75847
base: main
Are you sure you want to change the base?
Conversation
src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_CollectionExpression.cs
Outdated
Show resolved
Hide resolved
src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_CollectionExpression.cs
Outdated
Show resolved
Hide resolved
src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_CollectionExpression.cs
Show resolved
Hide resolved
src/Compilers/CSharp/Test/Emit3/Semantics/CollectionExpressionTests.cs
Outdated
Show resolved
Hide resolved
/// </summary> | ||
private BoundExpression CreateAndPopulateArray(BoundCollectionExpression node, ArrayTypeSymbol arrayType) | ||
/// <summary>Attempt to optimize conversion of a single-spread collection expr to array, even if the spread length is not known.</summary> | ||
private BoundExpression? TryOptimizeSingleSpreadToArray(BoundCollectionExpression node, ArrayTypeSymbol arrayType) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's now 3 possible optimizations this method will try, in order:
- List.ToArray if the spread value is a list
- IEnumerable.ToArray if our checks say we should convert the spread value in this way
- ReadOnlySpan.ToArray if we can convert the spread value to ReadOnlySpan
In my opinion this is the best order to try these, in part because IEnumerable.ToArray tends to produce less IL than the span conversions.
int[] arr1 = [..arr, ..arr]; | ||
arr1.Report(); | ||
} | ||
public static object[] M(string[] arr) => [..arr]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps test the following cases:
string[] x = ["a"];
M1(x);
M2(x);
static Span<object> M1(string[] arr) => [..arr];
static Span<object> M2(object[] arr) => [..arr];
using System; | ||
|
||
C.M1(["a"]); | ||
C.M2(["b"]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
C.M2(["b"])
creates an object[]
rather than a string[]
. Consider rewriting as:
string[] s = ["a"];
C.M1(s);
C.M2(s);
Closes #71296
Closes #71755
Some of these issues also discuss optimization in cases when multiple spreads of unknown length are present in the collection-expr, such as
[..e1, e2, ..e3]
and so on. I am thinking we should just handle the single spread case[..e]
for now as this is the source of majority of complaints. This is now handled by simply callingSystem.Linq.Enumerable.ToArray<T>(IEnumerable<T>)
in most cases when the spread value is convertible to IEnumerable.