Skip to content

Commit 83e65b6

Browse files
committed
C#: Implicit span conversion.
1 parent 98dc439 commit 83e65b6

File tree

1 file changed

+67
-4
lines changed

1 file changed

+67
-4
lines changed

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

Lines changed: 67 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,7 @@ 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+
private predicate convVarianceAux(UnboundGenericType ugt, GenericType fromType, GenericType toType) {
789839
// Semantically equivalent with
790840
// ```ql
791841
// ugt = fromType.getUnboundGeneric()
@@ -805,10 +855,23 @@ private predicate convVariance(GenericType fromType, GenericType toType) {
805855
// ```
806856
// but performance is improved by explicitly evaluating the `i`th argument
807857
// only when all preceding arguments are convertible.
808-
Variance::convVarianceSingle(_, fromType, toType)
858+
Variance::convVarianceSingle(ugt, fromType, toType)
809859
or
860+
Variance::convVarianceMultiple(ugt, fromType, toType, ugt.getNumberOfTypeParameters() - 1)
861+
}
862+
863+
/** 13.1.3.2: Variance conversion. */
864+
private predicate convVariance(GenericType fromType, GenericType toType) {
865+
convVarianceAux(_, fromType, toType)
866+
}
867+
868+
/**
869+
* Holds, if `fromType` is covariance convertible to `toType`.
870+
*/
871+
private predicate convCovariance(GenericType fromType, GenericType toType) {
810872
exists(UnboundGenericType ugt |
811-
Variance::convVarianceMultiple(ugt, fromType, toType, ugt.getNumberOfTypeParameters() - 1)
873+
convVarianceAux(ugt, fromType, toType) and
874+
forall(TypeParameter tp | tp = ugt.getATypeParameter() | tp.isOut())
812875
)
813876
}
814877

0 commit comments

Comments
 (0)