-
Notifications
You must be signed in to change notification settings - Fork 1.9k
C# 14: Implicit span conversions. #21065
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
C# 14: Implicit span conversions. #21065
Conversation
16a8982 to
741ef80
Compare
741ef80 to
1817f9c
Compare
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.
Pull request overview
This PR adds support for implicit span conversions in C# 14, allowing automatic conversions between arrays, Span<T>, and ReadOnlySpan<T> types. This language feature is now integrated into the CodeQL library to properly model these conversions during analysis.
Key changes:
- Implemented
convSpanpredicate to handle implicit span conversions including array-to-span, span-to-readonly-span, and string-to-readonly-span-of-char conversions - Added covariance support for span conversions through new
convCovariancehelper predicate - Added comprehensive test cases covering various span conversion scenarios
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
csharp/ql/lib/semmle/code/csharp/Conversion.qll |
Core implementation of span conversion logic and covariance helper |
csharp/ql/test/library-tests/conversion/span/Span.cs |
Test cases demonstrating various span conversion scenarios |
csharp/ql/test/library-tests/conversion/span/span.ql |
Query to verify span conversions are correctly identified |
csharp/ql/test/library-tests/conversion/span/span.expected |
Expected output for span conversion test cases |
csharp/ql/lib/change-notes/2025-12-18-implicit-span-conversions.md |
Release note documenting the new feature |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| private class SimpleArrayType extends ArrayType { | ||
| SimpleArrayType() { | ||
| this.getRank() = 1 and | ||
| this.getDimension() = 1 | ||
| } | ||
| } |
Copilot
AI
Dec 18, 2025
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.
The SimpleArrayType class lacks documentation explaining what distinguishes it from other array types. Add a docstring clarifying that this represents single-dimensional, zero-based arrays (SZ arrays), as getRank() = 1 and getDimension() = 1 restricts it to this specific array form.
hvitved
left a comment
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.
LGTM, two comments.
| | ReadOnlySpan<CovariantInterface<Derived>> | ReadOnlySpan<CovariantInterface<Base>> | | ||
| | Span<CovariantInterface<Derived>> | ReadOnlySpan<CovariantInterface<Base>> | | ||
| | Span<CovariantInterface<Derived>> | ReadOnlySpan<CovariantInterface<Derived>> | | ||
| | Span<Interface<Derived, string>> | ReadOnlySpan<Interface<Derived, string>> | |
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.
I would have expected something like
| Span<Interface<Derived, string>> | ReadOnlySpan<Interface<Base, string>> |
here?
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.
Uh, that is a very nice catch! The documentation on variance conversion is a bit sketchy and I mistakenly assumed that all type parameters needed to be declared out. However, as you point out (and this is also accepted by the compiler), identity conversions are also accepted for non-covariant type parameters.
I will improve this.
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.
It appears that the implicit conversions are allowed for all variance convertible types (and not only covariant convertible types as hinted in the documentation of the feature)
874dde9 to
b686890
Compare
|
|
||
| // Assignments are included to illustrate that it compiles. | ||
| // Only the use of the types matter in terms of test output. | ||
| // Covariant conversions to ReadOnlySpan |
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.
I think we need to add a test case for something like
ReadOnlySpan<Base> x = // something of type `Derived[]`;
ReadOnlySpan<Base> x = // something of type `Span<Derived>`;which I'm not sure the current logic is able to handle?
| | | ||
| convIdentity(fromElementType, toElementType) | ||
| or | ||
| convVariance(fromElementType, toElementType) |
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.
I think this should maybe be convRefTypeNonNull instead.
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.
Which should fix the issue I mention above.
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.
Thank you!
Yes, that I also what I am converging towards (started out with trying to use implicitConversionRestricted and then started narrowing and see how that aligns with what actually compiles).
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.
Yes, you are right!
hvitved
left a comment
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.
LGTM (assuming DCA is good).
|
DCA looks good. |
In this PR we introduce support for implicit span conversions. The feature is documented here. Even though the documentation states that this only applies to covariance convertible types (which is not defined), it appears that it is supported for all variance convertible types - and more generally all reference type conversions (between the element types).
That is, C# now supports implicit conversions to
ReadOnlySpan. Some of these were previously supported by implicit operators, but now they are an integrated part of the language. Here are some examples:There is out-of-the-box extractor support for this.
DCA looks good. Even though the content of the PR might affect some queries (like
cs/useless-upcast) it doesn't look like there are any changes to results.