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: align ConversionsBase.GetCollectionExpressionTypeKind() with spec #70975

Merged
merged 11 commits into from
Dec 12, 2023

Conversation

cston
Copy link
Member

@cston cston commented Nov 28, 2023

Update ConversionsBase.GetCollectionExpressionTypeKind() to check collection expressions for the conversions as defined in specification only.

The effect of this change is that recognizing whether to optimize List<T> and ImmutableArray<T> is now handled in lowering rather than initial binding, and the requirements for optimizing those types is tightened:

  • Optimizations for List<T> are no longer applied if there are dynamic elements, and
  • Optimizations for ImmutableArray<T> are only applied if the type has a [CollectionBuilder] attribute.

Fixes #70880

@dotnet-issue-labeler dotnet-issue-labeler bot added Area-Compilers untriaged Issues and PRs which have not yet been triaged by a lead labels Nov 28, 2023
@cston cston marked this pull request as ready for review November 30, 2023 05:57
@cston cston requested a review from a team as a code owner November 30, 2023 05:57
@@ -1638,23 +1638,14 @@ internal static CollectionExpressionTypeKind GetCollectionExpressionTypeKind(CSh
return CollectionExpressionTypeKind.Array;
}
}
Copy link
Contributor

@AlekseyTs AlekseyTs Nov 30, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}

Shouldn't we perform more checks for multi-dimensional arrays? #Closed

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the spec explicitly say that MD arrays are not valid targets?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MD arrays are not valid targets.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added clarification in dotnet/csharplang#7734.

@cston cston requested review from 333fred, RikkiGibson and a team December 5, 2023 18:18
@AlekseyTs
Copy link
Contributor

@333fred, @RikkiGibson Please review

@RikkiGibson RikkiGibson self-assigned this Dec 8, 2023
@AlekseyTs
Copy link
Contributor

@333fred, @RikkiGibson Please review

1 similar comment
@AlekseyTs
Copy link
Contributor

@333fred, @RikkiGibson Please review

@AlekseyTs
Copy link
Contributor

@RikkiGibson For the second review

@RikkiGibson
Copy link
Contributor

I'll try and take a look this afternoon. Thanks

@@ -128,7 +191,7 @@ private BoundExpression VisitArrayOrSpanCollectionExpression(BoundCollectionExpr

Debug.Assert(IsAllocatingRefStructCollectionExpression(node, collectionTypeKind, elementType.Type, _compilation));
arrayType = ArrayTypeSymbol.CreateSZArray(_compilation.Assembly, elementType);
spanConstructor = ((MethodSymbol)_compilation.GetWellKnownTypeMember(
spanConstructor = ((MethodSymbol)_factory.WellKnownMember(
Copy link
Contributor

@RikkiGibson RikkiGibson Dec 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: _factory.WellKnownMethod eliminates the need to cast #ByDesign

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, we're using _factory.WellKnownMethod() throughout this file, and in a number of other callsites in LocalRewriter where we could cast the result to MethodSymbol. Given that, I'll leave as-is, to reduce the churn.

@@ -674,7 +674,7 @@ void checkConstraintLanguageVersionAndRuntimeSupportForConversion(SyntaxNode syn
}
else
{
if ((collectionTypeKind is CollectionExpressionTypeKind.ArrayInterface or CollectionExpressionTypeKind.List) ||
if ((collectionTypeKind is CollectionExpressionTypeKind.ArrayInterface) ||
Copy link
Contributor

@RikkiGibson RikkiGibson Dec 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to check presence of these members when collectionTypeKind is CollectionInitializer? #ByDesign

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should only be using these methods for collection initializers when the target is List<T>, and in those cases, we'll bind to the methods in initial binding.

IL_0017: ldsfld "System.Runtime.CompilerServices.CallSite<System.Action<System.Runtime.CompilerServices.CallSite, System.Collections.Generic.List<object>, dynamic>> Program.<>o__0.<>p__0"
IL_001c: brtrue.s IL_005c
IL_001e: ldc.i4 0x100
IL_0023: ldstr "Add"
Copy link
Contributor

@RikkiGibson RikkiGibson Dec 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this dynamically invoking Add? I'm not sure I understand why codegen is changing in this test. #Resolved

Copy link
Member Author

@cston cston Dec 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is dynamically invoking Add(). (This implementation corresponds to the collection initializer approach - see sharplab.io.) We don't optimize if the elements include dynamic values.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason I was surprised is that the codegen before didn't appear to be optimized. Is that codegen from before actually optimized and that's why it's changing now?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the dynamic case was optimized previously.

IL_0015: stloc.2
IL_0016: ldloc.0
IL_0017: ldloc.2
IL_0018: callvirt "void System.Collections.Generic.List<object>.Add(string)"
Copy link
Contributor

@RikkiGibson RikkiGibson Dec 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

uh..which one? :) #Resolved

Copy link
Member Author

@cston cston Dec 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This uses the specialized List<object>.Add(string) rather than List<object>.Add(object).

Copy link
Contributor

@RikkiGibson RikkiGibson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done review pass. Had a few minor comments and questions.

@cston cston merged commit cfba8aa into dotnet:main Dec 12, 2023
@cston cston deleted the 70880 branch December 12, 2023 06:08
@ghost ghost added this to the Next milestone Dec 12, 2023
@Cosifne Cosifne modified the milestones: Next, 17.9 P3 Jan 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Compilers untriaged Issues and PRs which have not yet been triaged by a lead
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Collection expressions: align ConversionsBase.GetCollectionExpressionTypeKind() with conversions specification
5 participants