C#: Implicit span conversion.

This commit is contained in:
Michael Nebel
2025-12-18 11:49:32 +01:00
parent 98dc4390ea
commit 119ecff3b7

View File

@@ -28,6 +28,7 @@ private module Cached {
*
* - Identity conversions
* - Implicit numeric conversions
* - Implicit span conversions
* - Implicit nullable conversions
* - Implicit reference conversions
* - Boxing conversions
@@ -38,6 +39,8 @@ private module Cached {
or
convNumeric(fromType, toType)
or
convSpan(fromType, toType)
or
convNullableType(fromType, toType)
or
convRefTypeNonNull(fromType, toType)
@@ -81,6 +84,7 @@ private predicate implicitConversionNonNull(Type fromType, Type toType) {
*
* - Identity conversions
* - Implicit numeric conversions
* - Implicit span conversions
* - Implicit nullable conversions
* - Implicit reference conversions
* - Boxing conversions
@@ -491,6 +495,53 @@ private predicate convNumericChar(SimpleType toType) {
private predicate convNumericFloat(SimpleType toType) { toType instanceof DoubleType }
private class SpanType extends GenericType {
SpanType() { this.getUnboundGeneric() instanceof SystemSpanStruct }
Type getElementType() { result = this.getTypeArgument(0) }
}
private class ReadOnlySpanType extends GenericType {
ReadOnlySpanType() { this.getUnboundGeneric() instanceof SystemReadOnlySpanStruct }
Type getElementType() { result = this.getTypeArgument(0) }
}
private class SimpleArrayType extends ArrayType {
SimpleArrayType() {
this.getRank() = 1 and
this.getDimension() = 1
}
}
/**
* INTERNAL: Do not use.
*
* Holds if there is an implicit span conversion from `fromType` to `toType`.
*
* 10.2.1: Implicit span conversions (added in C# 14).
* [Documentation](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-14.0/first-class-span-types#span-conversions)
*/
predicate convSpan(Type fromType, Type toType) {
fromType.(SimpleArrayType).getElementType() = toType.(SpanType).getElementType()
or
exists(Type fromElementType, Type toElementType |
(
fromElementType = fromType.(SimpleArrayType).getElementType() or
fromElementType = fromType.(SpanType).getElementType() or
fromElementType = fromType.(ReadOnlySpanType).getElementType()
) and
toElementType = toType.(ReadOnlySpanType).getElementType()
|
convIdentity(fromElementType, toElementType)
or
convCovariance(fromElementType, toElementType)
)
or
fromType instanceof SystemStringClass and
toType.(ReadOnlySpanType).getElementType() instanceof CharType
}
/**
* INTERNAL: Do not use.
*
@@ -784,8 +835,8 @@ predicate convConversionOperator(Type fromType, Type toType) {
)
}
/** 13.1.3.2: Variance conversion. */
private predicate convVariance(GenericType fromType, GenericType toType) {
pragma[nomagic]
private predicate convVarianceAux(UnboundGenericType ugt, GenericType fromType, GenericType toType) {
// Semantically equivalent with
// ```ql
// ugt = fromType.getUnboundGeneric()
@@ -805,10 +856,23 @@ private predicate convVariance(GenericType fromType, GenericType toType) {
// ```
// but performance is improved by explicitly evaluating the `i`th argument
// only when all preceding arguments are convertible.
Variance::convVarianceSingle(_, fromType, toType)
Variance::convVarianceSingle(ugt, fromType, toType)
or
Variance::convVarianceMultiple(ugt, fromType, toType, ugt.getNumberOfTypeParameters() - 1)
}
/** 13.1.3.2: Variance conversion. */
private predicate convVariance(GenericType fromType, GenericType toType) {
convVarianceAux(_, fromType, toType)
}
/**
* Holds, if `fromType` is covariance convertible to `toType`.
*/
private predicate convCovariance(GenericType fromType, GenericType toType) {
exists(UnboundGenericType ugt |
Variance::convVarianceMultiple(ugt, fromType, toType, ugt.getNumberOfTypeParameters() - 1)
convVarianceAux(ugt, fromType, toType) and
forall(TypeParameter tp | tp = ugt.getATypeParameter() | tp.isOut())
)
}