Skip to content

Commit 119ecff

Browse files
committed
C#: Implicit span conversion.
1 parent 98dc439 commit 119ecff

File tree

1 file changed

+68
-4
lines changed

1 file changed

+68
-4
lines changed

csharp/ql/lib/semmle/code/csharp/Conversion.qll

Lines changed: 68 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ private module Cached {
2828
*
2929
* - Identity conversions
3030
* - Implicit numeric conversions
31+
* - Implicit span conversions
3132
* - Implicit nullable conversions
3233
* - Implicit reference conversions
3334
* - Boxing conversions
@@ -38,6 +39,8 @@ private module Cached {
3839
or
3940
convNumeric(fromType, toType)
4041
or
42+
convSpan(fromType, toType)
43+
or
4144
convNullableType(fromType, toType)
4245
or
4346
convRefTypeNonNull(fromType, toType)
@@ -81,6 +84,7 @@ private predicate implicitConversionNonNull(Type fromType, Type toType) {
8184
*
8285
* - Identity conversions
8386
* - Implicit numeric conversions
87+
* - Implicit span conversions
8488
* - Implicit nullable conversions
8589
* - Implicit reference conversions
8690
* - Boxing conversions
@@ -491,6 +495,53 @@ private predicate convNumericChar(SimpleType toType) {
491495

492496
private predicate convNumericFloat(SimpleType toType) { toType instanceof DoubleType }
493497

498+
private class SpanType extends GenericType {
499+
SpanType() { this.getUnboundGeneric() instanceof SystemSpanStruct }
500+
501+
Type getElementType() { result = this.getTypeArgument(0) }
502+
}
503+
504+
private class ReadOnlySpanType extends GenericType {
505+
ReadOnlySpanType() { this.getUnboundGeneric() instanceof SystemReadOnlySpanStruct }
506+
507+
Type getElementType() { result = this.getTypeArgument(0) }
508+
}
509+
510+
private class SimpleArrayType extends ArrayType {
511+
SimpleArrayType() {
512+
this.getRank() = 1 and
513+
this.getDimension() = 1
514+
}
515+
}
516+
517+
/**
518+
* INTERNAL: Do not use.
519+
*
520+
* Holds if there is an implicit span conversion from `fromType` to `toType`.
521+
*
522+
* 10.2.1: Implicit span conversions (added in C# 14).
523+
* [Documentation](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-14.0/first-class-span-types#span-conversions)
524+
*/
525+
predicate convSpan(Type fromType, Type toType) {
526+
fromType.(SimpleArrayType).getElementType() = toType.(SpanType).getElementType()
527+
or
528+
exists(Type fromElementType, Type toElementType |
529+
(
530+
fromElementType = fromType.(SimpleArrayType).getElementType() or
531+
fromElementType = fromType.(SpanType).getElementType() or
532+
fromElementType = fromType.(ReadOnlySpanType).getElementType()
533+
) and
534+
toElementType = toType.(ReadOnlySpanType).getElementType()
535+
|
536+
convIdentity(fromElementType, toElementType)
537+
or
538+
convCovariance(fromElementType, toElementType)
539+
)
540+
or
541+
fromType instanceof SystemStringClass and
542+
toType.(ReadOnlySpanType).getElementType() instanceof CharType
543+
}
544+
494545
/**
495546
* INTERNAL: Do not use.
496547
*
@@ -784,8 +835,8 @@ predicate convConversionOperator(Type fromType, Type toType) {
784835
)
785836
}
786837

787-
/** 13.1.3.2: Variance conversion. */
788-
private predicate convVariance(GenericType fromType, GenericType toType) {
838+
pragma[nomagic]
839+
private predicate convVarianceAux(UnboundGenericType ugt, GenericType fromType, GenericType toType) {
789840
// Semantically equivalent with
790841
// ```ql
791842
// ugt = fromType.getUnboundGeneric()
@@ -805,10 +856,23 @@ private predicate convVariance(GenericType fromType, GenericType toType) {
805856
// ```
806857
// but performance is improved by explicitly evaluating the `i`th argument
807858
// only when all preceding arguments are convertible.
808-
Variance::convVarianceSingle(_, fromType, toType)
859+
Variance::convVarianceSingle(ugt, fromType, toType)
809860
or
861+
Variance::convVarianceMultiple(ugt, fromType, toType, ugt.getNumberOfTypeParameters() - 1)
862+
}
863+
864+
/** 13.1.3.2: Variance conversion. */
865+
private predicate convVariance(GenericType fromType, GenericType toType) {
866+
convVarianceAux(_, fromType, toType)
867+
}
868+
869+
/**
870+
* Holds, if `fromType` is covariance convertible to `toType`.
871+
*/
872+
private predicate convCovariance(GenericType fromType, GenericType toType) {
810873
exists(UnboundGenericType ugt |
811-
Variance::convVarianceMultiple(ugt, fromType, toType, ugt.getNumberOfTypeParameters() - 1)
874+
convVarianceAux(ugt, fromType, toType) and
875+
forall(TypeParameter tp | tp = ugt.getATypeParameter() | tp.isOut())
812876
)
813877
}
814878

0 commit comments

Comments
 (0)