FIR2IR: properly set constant expression type

This commit is contained in:
Mikhail Glukhikh
2023-06-26 16:00:53 +03:00
committed by Space Team
parent 09175c7d56
commit 71456c5514
12 changed files with 172 additions and 58 deletions
@@ -390,7 +390,7 @@ internal object FirCompileTimeConstantEvaluator {
private fun <T> ConstantValueKind<T>.toConstExpression(source: KtSourceElement?, value: Any?): FirConstExpression<T> = private fun <T> ConstantValueKind<T>.toConstExpression(source: KtSourceElement?, value: Any?): FirConstExpression<T> =
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
buildConstExpression(source, this, value as T) buildConstExpression(source, this, value as T, setType = false)
private fun FirFunctionCall.getOriginalFunction(): FirCallableDeclaration? { private fun FirFunctionCall.getOriginalFunction(): FirCallableDeclaration? {
val symbol: FirBasedSymbol<*>? = when (val reference = calleeReference) { val symbol: FirBasedSymbol<*>? = when (val reference = calleeReference) {
@@ -215,7 +215,8 @@ internal open class FirElementsRecorder : FirVisitor<Unit, MutableMap<KtElement,
return buildConstExpression( return buildConstExpression(
original.ktConstantExpression?.toKtPsiSourceElement(), original.ktConstantExpression?.toKtPsiSourceElement(),
this, this,
convertedValue as T convertedValue as T,
setType = false
).also { ).also {
it.replaceTypeRef(original.typeRef) it.replaceTypeRef(original.typeRef)
} }
@@ -35,16 +35,33 @@ fun buildFirConstant(
protoValue: ProtoBuf.Annotation.Argument.Value?, sourceValue: Any?, constKind: String, nameResolver: NameResolver protoValue: ProtoBuf.Annotation.Argument.Value?, sourceValue: Any?, constKind: String, nameResolver: NameResolver
): FirExpression? { ): FirExpression? {
return when (constKind) { return when (constKind) {
"BYTE", "B" -> buildConstExpression(null, ConstantValueKind.Byte, ((protoValue?.intValue ?: sourceValue) as Number).toByte()) "BYTE", "B" -> buildConstExpression(
"CHAR", "C" -> buildConstExpression(null, ConstantValueKind.Char, ((protoValue?.intValue ?: sourceValue) as Number).toInt().toChar()) null, ConstantValueKind.Byte, ((protoValue?.intValue ?: sourceValue) as Number).toByte(), setType = true
"SHORT", "S" -> buildConstExpression(null, ConstantValueKind.Short, ((protoValue?.intValue ?: sourceValue) as Number).toShort()) )
"INT", "I" -> buildConstExpression(null, ConstantValueKind.Int, protoValue?.intValue?.toInt() ?: sourceValue as Int) "CHAR", "C" -> buildConstExpression(
"LONG", "J" -> buildConstExpression(null, ConstantValueKind.Long, protoValue?.intValue ?: sourceValue as Long) null, ConstantValueKind.Char, ((protoValue?.intValue ?: sourceValue) as Number).toInt().toChar(), setType = true
"FLOAT", "F" -> buildConstExpression(null, ConstantValueKind.Float, protoValue?.floatValue ?: sourceValue as Float) )
"DOUBLE", "D" -> buildConstExpression(null, ConstantValueKind.Double, protoValue?.doubleValue ?: sourceValue as Double) "SHORT", "S" -> buildConstExpression(
"BOOLEAN", "Z" -> buildConstExpression(null, ConstantValueKind.Boolean, (protoValue?.intValue?.toInt() ?: sourceValue) != 0) null, ConstantValueKind.Short, ((protoValue?.intValue ?: sourceValue) as Number).toShort(), setType = true
)
"INT", "I" -> buildConstExpression(
null, ConstantValueKind.Int, protoValue?.intValue?.toInt() ?: sourceValue as Int, setType = true
)
"LONG", "J" -> buildConstExpression(
null, ConstantValueKind.Long, protoValue?.intValue ?: sourceValue as Long, setType = true
)
"FLOAT", "F" -> buildConstExpression(
null, ConstantValueKind.Float, protoValue?.floatValue ?: sourceValue as Float, setType = true
)
"DOUBLE", "D" -> buildConstExpression(
null, ConstantValueKind.Double, protoValue?.doubleValue ?: sourceValue as Double, setType = true
)
"BOOLEAN", "Z" -> buildConstExpression(
null, ConstantValueKind.Boolean, (protoValue?.intValue?.toInt() ?: sourceValue) != 0, setType = true
)
"STRING", "Ljava/lang/String;" -> buildConstExpression( "STRING", "Ljava/lang/String;" -> buildConstExpression(
null, ConstantValueKind.String, protoValue?.stringValue?.let { nameResolver.getString(it) } ?: sourceValue as String null, ConstantValueKind.String,
protoValue?.stringValue?.let { nameResolver.getString(it) } ?: sourceValue as String, setType = true
) )
else -> null else -> null
} }
@@ -467,6 +467,7 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) {
proto.contextReceiverTypes(c.typeTable).mapTo(contextReceivers, ::loadContextReceiver) proto.contextReceiverTypes(c.typeTable).mapTo(contextReceivers, ::loadContextReceiver)
}.apply { }.apply {
initializer?.replaceTypeRef(returnTypeRef)
versionRequirementsTable = c.versionRequirementTable versionRequirementsTable = c.versionRequirementTable
setLazyPublishedVisibility(c.session) setLazyPublishedVisibility(c.session)
getter?.setLazyPublishedVisibility(annotations, this, c.session) getter?.setLazyPublishedVisibility(annotations, this, c.session)
@@ -600,7 +600,9 @@ class FirElementSerializer private constructor(
} }
} }
private fun typeAliasProto(typeAlias: FirTypeAlias): ProtoBuf.TypeAlias.Builder? = whileAnalysing<ProtoBuf.TypeAlias.Builder?>(session, typeAlias) { private fun typeAliasProto(typeAlias: FirTypeAlias): ProtoBuf.TypeAlias.Builder? = whileAnalysing<ProtoBuf.TypeAlias.Builder?>(
session, typeAlias
) {
val builder = ProtoBuf.TypeAlias.newBuilder() val builder = ProtoBuf.TypeAlias.newBuilder()
val local = createChildSerializer(typeAlias) val local = createChildSerializer(typeAlias)
@@ -851,7 +853,9 @@ class FirElementSerializer private constructor(
correspondingTypeRef?.annotations, CompilerConeAttributes.ContextFunctionTypeParams.ANNOTATION_CLASS_ID, correspondingTypeRef?.annotations, CompilerConeAttributes.ContextFunctionTypeParams.ANNOTATION_CLASS_ID,
argumentMapping = buildAnnotationArgumentMapping { argumentMapping = buildAnnotationArgumentMapping {
this.mapping[StandardNames.CONTEXT_FUNCTION_TYPE_PARAMETER_COUNT_NAME] = this.mapping[StandardNames.CONTEXT_FUNCTION_TYPE_PARAMETER_COUNT_NAME] =
buildConstExpression(source = null, ConstantValueKind.Int, type.contextReceiversNumberForFunctionType) buildConstExpression(
source = null, ConstantValueKind.Int, type.contextReceiversNumberForFunctionType, setType = false
)
} }
) )
) )
@@ -117,16 +117,66 @@ class Fir2IrAnnotationsFromPluginRegistrar(private val components: Fir2IrCompone
val name = this@toFirAnnotation.symbol.owner.valueParameters[i].name val name = this@toFirAnnotation.symbol.owner.valueParameters[i].name
val argument = this@toFirAnnotation.getValueArgument(i) as IrConst<*> val argument = this@toFirAnnotation.getValueArgument(i) as IrConst<*>
this.mapping[name] = when (argument.kind) { this.mapping[name] = when (argument.kind) {
IrConstKind.Boolean -> buildConstExpression(source = null, ConstantValueKind.Boolean, argument.value as Boolean) IrConstKind.Boolean -> buildConstExpression(
IrConstKind.Byte -> buildConstExpression(source = null, ConstantValueKind.Byte, argument.value as Byte) source = null,
IrConstKind.Char -> buildConstExpression(source = null, ConstantValueKind.Char, argument.value as Char) ConstantValueKind.Boolean,
IrConstKind.Double -> buildConstExpression(source = null, ConstantValueKind.Double, argument.value as Double) argument.value as Boolean,
IrConstKind.Float -> buildConstExpression(source = null, ConstantValueKind.Float, argument.value as Float) setType = true
IrConstKind.Int -> buildConstExpression(source = null, ConstantValueKind.Int, argument.value as Int) )
IrConstKind.Long -> buildConstExpression(source = null, ConstantValueKind.Long, argument.value as Long) IrConstKind.Byte -> buildConstExpression(
IrConstKind.Null -> buildConstExpression(source = null, ConstantValueKind.Null, null) source = null,
IrConstKind.Short -> buildConstExpression(source = null, ConstantValueKind.Short, argument.value as Short) ConstantValueKind.Byte,
IrConstKind.String -> buildConstExpression(source = null, ConstantValueKind.String, argument.value as String) argument.value as Byte,
setType = true
)
IrConstKind.Char -> buildConstExpression(
source = null,
ConstantValueKind.Char,
argument.value as Char,
setType = true
)
IrConstKind.Double -> buildConstExpression(
source = null,
ConstantValueKind.Double,
argument.value as Double,
setType = true
)
IrConstKind.Float -> buildConstExpression(
source = null,
ConstantValueKind.Float,
argument.value as Float,
setType = true
)
IrConstKind.Int -> buildConstExpression(
source = null,
ConstantValueKind.Int,
argument.value as Int,
setType = true
)
IrConstKind.Long -> buildConstExpression(
source = null,
ConstantValueKind.Long,
argument.value as Long,
setType = true
)
IrConstKind.Null -> buildConstExpression(
source = null,
ConstantValueKind.Null,
value = null,
setType = true
)
IrConstKind.Short -> buildConstExpression(
source = null,
ConstantValueKind.Short,
argument.value as Short,
setType = false
)
IrConstKind.String -> buildConstExpression(
source = null,
ConstantValueKind.String,
argument.value as String,
setType = false
)
} }
} }
} }
@@ -63,15 +63,33 @@ internal fun Any?.createConstantOrError(session: FirSession): FirExpression {
internal fun Any?.createConstantIfAny(session: FirSession, unsigned: Boolean = false): FirExpression? { internal fun Any?.createConstantIfAny(session: FirSession, unsigned: Boolean = false): FirExpression? {
return when (this) { return when (this) {
is Byte -> buildConstExpression(null, if (unsigned) ConstantValueKind.UnsignedByte else ConstantValueKind.Byte, this).setProperType(session) is Byte -> buildConstExpression(
is Short -> buildConstExpression(null, if (unsigned) ConstantValueKind.UnsignedShort else ConstantValueKind.Short, this).setProperType(session) null, if (unsigned) ConstantValueKind.UnsignedByte else ConstantValueKind.Byte, this, setType = true
is Int -> buildConstExpression(null, if (unsigned) ConstantValueKind.UnsignedInt else ConstantValueKind.Int, this).setProperType(session) )
is Long -> buildConstExpression(null, if (unsigned) ConstantValueKind.UnsignedLong else ConstantValueKind.Long, this).setProperType(session) is Short -> buildConstExpression(
is Char -> buildConstExpression(null, ConstantValueKind.Char, this).setProperType(session) null, if (unsigned) ConstantValueKind.UnsignedShort else ConstantValueKind.Short, this, setType = true
is Float -> buildConstExpression(null, ConstantValueKind.Float, this).setProperType(session) )
is Double -> buildConstExpression(null, ConstantValueKind.Double, this).setProperType(session) is Int -> buildConstExpression(
is Boolean -> buildConstExpression(null, ConstantValueKind.Boolean, this).setProperType(session) null, if (unsigned) ConstantValueKind.UnsignedInt else ConstantValueKind.Int, this, setType = true
is String -> buildConstExpression(null, ConstantValueKind.String, this).setProperType(session) )
is Long -> buildConstExpression(
null, if (unsigned) ConstantValueKind.UnsignedLong else ConstantValueKind.Long, this, setType = true
)
is Char -> buildConstExpression(
null, ConstantValueKind.Char, this, setType = true
)
is Float -> buildConstExpression(
null, ConstantValueKind.Float, this, setType = true
)
is Double -> buildConstExpression(
null, ConstantValueKind.Double, this, setType = true
)
is Boolean -> buildConstExpression(
null, ConstantValueKind.Boolean, this, setType = true
)
is String -> buildConstExpression(
null, ConstantValueKind.String, this, setType = true
)
is ByteArray -> toList().createArrayOfCall(session, ConstantValueKind.Byte) is ByteArray -> toList().createArrayOfCall(session, ConstantValueKind.Byte)
is ShortArray -> toList().createArrayOfCall(session, ConstantValueKind.Short) is ShortArray -> toList().createArrayOfCall(session, ConstantValueKind.Short)
is IntArray -> toList().createArrayOfCall(session, ConstantValueKind.Int) is IntArray -> toList().createArrayOfCall(session, ConstantValueKind.Int)
@@ -80,7 +98,9 @@ internal fun Any?.createConstantIfAny(session: FirSession, unsigned: Boolean = f
is FloatArray -> toList().createArrayOfCall(session, ConstantValueKind.Float) is FloatArray -> toList().createArrayOfCall(session, ConstantValueKind.Float)
is DoubleArray -> toList().createArrayOfCall(session, ConstantValueKind.Double) is DoubleArray -> toList().createArrayOfCall(session, ConstantValueKind.Double)
is BooleanArray -> toList().createArrayOfCall(session, ConstantValueKind.Boolean) is BooleanArray -> toList().createArrayOfCall(session, ConstantValueKind.Boolean)
null -> buildConstExpression(null, ConstantValueKind.Null, null).setProperType(session) null -> buildConstExpression(
null, ConstantValueKind.Null, null, setType = true
)
else -> null else -> null
} }
@@ -99,14 +119,6 @@ private fun <T> List<T>.createArrayOfCall(session: FirSession, kind: ConstantVal
} }
} }
private fun FirConstExpression<*>.setProperType(session: FirSession): FirConstExpression<*> {
val typeRef = buildResolvedTypeRef {
type = kind.expectedConeType(session)
}
replaceTypeRef(typeRef)
return this
}
// For now, it's supported only for RxJava3 annotations, see KT-53041 // For now, it's supported only for RxJava3 annotations, see KT-53041
fun extractNullabilityAnnotationOnBoundedWildcard(wildcardType: JavaWildcardType): JavaAnnotation? { fun extractNullabilityAnnotationOnBoundedWildcard(wildcardType: JavaWildcardType): JavaAnnotation? {
require(wildcardType.bound != null) { "Nullability annotations on unbounded wildcards aren't supported" } require(wildcardType.bound != null) { "Nullability annotations on unbounded wildcards aren't supported" }
@@ -406,13 +406,15 @@ abstract class AbstractRawFirBuilder<T>(val baseSession: FirSession, val context
buildConstExpression( buildConstExpression(
sourceElement, sourceElement,
ConstantValueKind.Boolean, ConstantValueKind.Boolean,
convertedText as Boolean convertedText as Boolean,
setType = false
) )
NULL -> NULL ->
buildConstExpression( buildConstExpression(
sourceElement, sourceElement,
ConstantValueKind.Null, ConstantValueKind.Null,
null null,
setType = false
) )
else -> else ->
throw AssertionError("Unknown literal type: $type, $text") throw AssertionError("Unknown literal type: $type, $text")
@@ -438,7 +440,8 @@ abstract class AbstractRawFirBuilder<T>(val baseSession: FirSession, val context
return buildConstExpression( return buildConstExpression(
source.toFirSourceElement(), source.toFirSourceElement(),
ConstantValueKind.IntegerLiteral, ConstantValueKind.IntegerLiteral,
convertedValue convertedValue,
setType = false
) )
} }
@@ -457,11 +460,15 @@ abstract class AbstractRawFirBuilder<T>(val baseSession: FirSession, val context
OPEN_QUOTE, CLOSING_QUOTE -> continue@L OPEN_QUOTE, CLOSING_QUOTE -> continue@L
LITERAL_STRING_TEMPLATE_ENTRY -> { LITERAL_STRING_TEMPLATE_ENTRY -> {
sb.append(entry.asText) sb.append(entry.asText)
buildConstExpression(entry.toFirSourceElement(), ConstantValueKind.String, entry.asText) buildConstExpression(
entry.toFirSourceElement(), ConstantValueKind.String, entry.asText, setType = false
)
} }
ESCAPE_STRING_TEMPLATE_ENTRY -> { ESCAPE_STRING_TEMPLATE_ENTRY -> {
sb.append(entry.unescapedValue) sb.append(entry.unescapedValue)
buildConstExpression(entry.toFirSourceElement(), ConstantValueKind.String, entry.unescapedValue) buildConstExpression(
entry.toFirSourceElement(), ConstantValueKind.String, entry.unescapedValue, setType = false
)
} }
SHORT_STRING_TEMPLATE_ENTRY, LONG_STRING_TEMPLATE_ENTRY -> { SHORT_STRING_TEMPLATE_ENTRY, LONG_STRING_TEMPLATE_ENTRY -> {
hasExpressions = true hasExpressions = true
@@ -479,7 +486,7 @@ abstract class AbstractRawFirBuilder<T>(val baseSession: FirSession, val context
} }
source = base?.toFirSourceElement() source = base?.toFirSourceElement()
// Fast-pass if there is no non-const string expressions // Fast-pass if there is no non-const string expressions
if (!hasExpressions) return buildConstExpression(source, ConstantValueKind.String, sb.toString()) if (!hasExpressions) return buildConstExpression(source, ConstantValueKind.String, sb.toString(), setType = false)
} }
} }
@@ -355,7 +355,7 @@ fun <T> FirPropertyBuilder.generateAccessorsByDelegate(
type = context.dispatchReceiverTypesStack.last() type = context.dispatchReceiverTypesStack.last()
} }
} }
else -> buildConstExpression(null, ConstantValueKind.Null, null) else -> buildConstExpression(null, ConstantValueKind.Null, null, setType = false)
} }
fun delegateAccess() = buildPropertyAccessExpression { fun delegateAccess() = buildPropertyAccessExpression {
@@ -38,7 +38,7 @@ inline val FirAnnotation.unexpandedClassId: ClassId?
fun <T> buildConstOrErrorExpression(source: KtSourceElement?, kind: ConstantValueKind<T>, value: T?, diagnostic: ConeDiagnostic): FirExpression = fun <T> buildConstOrErrorExpression(source: KtSourceElement?, kind: ConstantValueKind<T>, value: T?, diagnostic: ConeDiagnostic): FirExpression =
value?.let { value?.let {
buildConstExpression(source, kind, it) buildConstExpression(source, kind, it, setType = false)
} ?: buildErrorExpression { } ?: buildErrorExpression {
this.source = source this.source = source
this.diagnostic = diagnostic this.diagnostic = diagnostic
@@ -18,18 +18,30 @@ fun <T> buildConstExpression(
kind: ConstantValueKind<T>, kind: ConstantValueKind<T>,
value: T, value: T,
annotations: MutableList<FirAnnotation> = mutableListOf(), annotations: MutableList<FirAnnotation> = mutableListOf(),
setType: Boolean = false setType: Boolean
): FirConstExpression<T> { ): FirConstExpression<T> {
return FirConstExpressionImpl(source, annotations.toMutableOrEmpty(), kind, value).also { return FirConstExpressionImpl(source, annotations.toMutableOrEmpty(), kind, value).also {
if (setType) { if (setType) {
when (value) { when (kind) {
null -> it.typeRef = FirImplicitNullableAnyTypeRef(null) ConstantValueKind.Boolean -> it.typeRef = FirImplicitBooleanTypeRef(null)
is String -> it.typeRef = FirImplicitStringTypeRef(null) ConstantValueKind.Byte -> it.typeRef = FirImplicitByteTypeRef(null)
is Long -> it.typeRef = FirImplicitLongTypeRef(null) ConstantValueKind.Char -> it.typeRef = FirImplicitCharTypeRef(null)
is Int -> it.typeRef = FirImplicitIntTypeRef(null) ConstantValueKind.Double -> it.typeRef = FirImplicitDoubleTypeRef(null)
is Boolean -> it.typeRef = FirImplicitBooleanTypeRef(null) ConstantValueKind.Float -> it.typeRef = FirImplicitFloatTypeRef(null)
is Double -> it.typeRef = FirImplicitDoubleTypeRef(null) ConstantValueKind.Int -> it.typeRef = FirImplicitIntTypeRef(null)
is Float -> it.typeRef = FirImplicitFloatTypeRef(null) ConstantValueKind.Long -> it.typeRef = FirImplicitLongTypeRef(null)
ConstantValueKind.Null -> it.typeRef = FirImplicitNullableAnyTypeRef(null)
ConstantValueKind.Short -> it.typeRef = FirImplicitShortTypeRef(null)
ConstantValueKind.String -> it.typeRef = FirImplicitStringTypeRef(null)
ConstantValueKind.UnsignedByte -> it.typeRef = FirImplicitUByteTypeRef(null)
ConstantValueKind.UnsignedInt -> it.typeRef = FirImplicitUIntTypeRef(null)
ConstantValueKind.UnsignedLong -> it.typeRef = FirImplicitULongTypeRef(null)
ConstantValueKind.UnsignedShort -> it.typeRef = FirImplicitUShortTypeRef(null)
ConstantValueKind.IntegerLiteral,
ConstantValueKind.UnsignedIntegerLiteral,
ConstantValueKind.Error,
-> {
}
} }
} }
} }
@@ -106,6 +106,14 @@ class FirImplicitULongTypeRef(
source: KtSourceElement? source: KtSourceElement?
) : FirImplicitBuiltinTypeRef(source, StandardClassIds.ULong) ) : FirImplicitBuiltinTypeRef(source, StandardClassIds.ULong)
class FirImplicitUShortTypeRef(
source: KtSourceElement?
) : FirImplicitBuiltinTypeRef(source, StandardClassIds.UShort)
class FirImplicitUByteTypeRef(
source: KtSourceElement?
) : FirImplicitBuiltinTypeRef(source, StandardClassIds.UByte)
class FirImplicitNothingTypeRef( class FirImplicitNothingTypeRef(
source: KtSourceElement? source: KtSourceElement?
) : FirImplicitBuiltinTypeRef(source, StandardClassIds.Nothing) ) : FirImplicitBuiltinTypeRef(source, StandardClassIds.Nothing)
@@ -241,5 +249,7 @@ fun FirImplicitBuiltinTypeRef.withNewSource(newSource: KtSourceElement?): FirImp
extensionReceiverTypeArgument = type.typeArguments[1], extensionReceiverTypeArgument = type.typeArguments[1],
propertyTypeArgument = type.typeArguments[2] propertyTypeArgument = type.typeArguments[2]
) )
is FirImplicitUByteTypeRef -> FirImplicitUByteTypeRef(newSource)
is FirImplicitUShortTypeRef -> FirImplicitUShortTypeRef(newSource)
} }
} }