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

Warn if collection expression to ref struct type incurs a heap allocation #70264

Merged
merged 1 commit into from
Oct 13, 2023

Conversation

RikkiGibson
Copy link
Contributor

@RikkiGibson RikkiGibson commented Oct 6, 2023

Closes #69693
Changes from #70260 will appear in this PR until main is synced again. They're pretty small and since they only affect codegen they're distinct from the diagnostic changes.

@dotnet-issue-labeler dotnet-issue-labeler bot added Area-Compilers untriaged Issues and PRs which have not yet been triaged by a lead labels Oct 6, 2023
@RikkiGibson RikkiGibson force-pushed the warn-ref-struct-alloc branch from 551a908 to 3ca6fef Compare October 9, 2023 23:55
@RikkiGibson RikkiGibson changed the base branch from features/CollectionLiterals to main October 9, 2023 23:55
@RikkiGibson RikkiGibson marked this pull request as ready for review October 9, 2023 23:59
@RikkiGibson RikkiGibson requested a review from a team as a code owner October 9, 2023 23:59
@@ -98,16 +98,25 @@ private BoundExpression VisitArrayOrSpanCollectionExpression(BoundCollectionExpr
collectionTypeKind == CollectionExpressionTypeKind.Span ? WellKnownType.System_Span_T : WellKnownType.System_ReadOnlySpan_T), TypeCompareKind.AllIgnoreOptions));
Debug.Assert(elementType.Equals(spanType.TypeArgumentsWithAnnotationsNoUseSiteDiagnostics[0], TypeCompareKind.AllIgnoreOptions));

if (elements.Length == 0)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I felt it was worth basing this PR on #70260 because the presence of the optimization affects whether we want to give this warning.

{
diagnostics.Add(node.HasSpreadElements(out _, out _)
? ErrorCode.WRN_CollectionExpressionRefStructSpreadMayAllocate
: ErrorCode.WRN_CollectionExpressionRefStructMayAllocate,
Copy link
Member

Choose a reason for hiding this comment

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

Looks like if a user gets the former warning, then removes spreads they might still get the latter warning - isn't that confusing?

Copy link
Contributor Author

@RikkiGibson RikkiGibson Oct 10, 2023

Choose a reason for hiding this comment

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

It could def be inconvenient to address one warning and then have another warning pop up. However, I think giving a more precise answer here could require us to more deeply analyze the collection-expr, e.g. if the spread element were removed, would we be able to use the ROS optimization based on the type and other elements? Would we be able to use InlineArray?

The main goal of having multiple diagnostic IDs is to allow end users to choose a different policy for "allocating because of spreads" versus "allocating due to lack of runtime support". I think for the audience we expect to be consuming this warning, the current behavior is adequate.

comp.VerifyEmitDiagnostics(
// 0.cs(12,60): warning CS9208: Collection expression of type 'MyCollection<T>' may incur unexpected heap allocations. Consider explicitly creating an array, then converting to 'MyCollection<T>' to make the allocation explicit.
Copy link
Member

@cston cston Oct 11, 2023

Choose a reason for hiding this comment

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

Consider explicitly creating an array, then converting to 'MyCollection' to make the allocation explicit.

The recommendation is not clear to me for types with a [CollectionBuilder] attribute. Is the expectation to call MyCollectionBuilder.Create((T[])[x, y, z]) for this case?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Since the user-defined ref structs are always exposing some Create(ROS<...>) method, we know the ref struct can always be created from an array. You're right that MyCollectionBuilder.Create((T[])[x, y, z]) can be used in this case. I could include the symbol in the diagnostic message for reference if you think that would be helpful.

@RikkiGibson RikkiGibson force-pushed the warn-ref-struct-alloc branch from c9e4d3f to b6a45c0 Compare October 13, 2023 20:33
@RikkiGibson
Copy link
Contributor Author

Rebasing to clean up the diff with main

@RikkiGibson RikkiGibson merged commit e637e05 into dotnet:main Oct 13, 2023
25 checks passed
@RikkiGibson RikkiGibson deleted the warn-ref-struct-alloc branch October 13, 2023 23:48
@ghost ghost added this to the Next milestone Oct 13, 2023
@RikkiGibson
Copy link
Contributor Author

Commit message isn't perfectly accurate, this warning only applies to span types. Apologies for any confusion.

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: Report warning when the compiler generates a heap allocation for a ref struct
3 participants