[FIR] Initialize type for annotation arguments during deserialization

Get rid of IrErrorTypeImpl creating in FIR2IR
This commit is contained in:
Ivan Kochurkin
2022-04-27 15:57:29 +03:00
parent 0ef043b074
commit ad7c213ab2
18 changed files with 133 additions and 54 deletions
@@ -33,6 +33,7 @@ import org.jetbrains.kotlin.metadata.deserialization.NameResolver
import org.jetbrains.kotlin.metadata.deserialization.TypeTable
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.StandardClassIds
import org.jetbrains.kotlin.protobuf.MessageLite
import org.jetbrains.kotlin.serialization.deserialization.builtins.BuiltInSerializerProtocol
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource
@@ -254,13 +255,16 @@ abstract class AbstractAnnotationDeserializer(
val classId = nameResolver.getClassId(value.classId)
val lookupTag = ConeClassLikeLookupTagImpl(classId)
val referencedType = lookupTag.constructType(emptyArray(), isNullable = false)
val resolvedTypeRef = buildResolvedTypeRef {
type = StandardClassIds.KClass.constructClassLikeType(arrayOf(referencedType), false)
}
argumentList = buildUnaryArgumentList(
buildClassReferenceExpression {
classTypeRef = buildResolvedTypeRef {
type = referencedType
}
classTypeRef = buildResolvedTypeRef { type = referencedType }
typeRef = resolvedTypeRef
}
)
typeRef = resolvedTypeRef
}
ENUM -> buildFunctionCall {
val classId = nameResolver.getClassId(value.classId)
@@ -280,6 +284,9 @@ abstract class AbstractAnnotationDeserializer(
diagnostic =
ConeSimpleDiagnostic("Strange deserialized enum value: $classId.$entryName", DiagnosticKind.DeserializationError)
}
if (enumEntrySymbol != null) {
typeRef = enumEntrySymbol.returnTypeRef
}
}
ARRAY -> {
val expectedArrayElementType = expectedType()?.arrayElementType() ?: session.builtinTypes.anyType.type
@@ -1173,18 +1173,11 @@ class Fir2IrVisitor(
private fun convertToArrayOfCall(arrayOfCall: FirArrayOfCall, annotationMode: Boolean): IrVararg {
return arrayOfCall.convertWithOffsets { startOffset, endOffset ->
lateinit var elementType: IrType
lateinit var arrayType: IrType
// Resolved arrayOf call will have resolved type. FirArrayOfCall from collection literal won't.
if (arrayOfCall.typeRef is FirResolvedTypeRef) {
arrayType = arrayOfCall.typeRef.toIrType()
elementType = arrayType.getArrayElementType(irBuiltIns)
val arrayType = arrayOfCall.typeRef.toIrType()
val elementType = if (arrayOfCall.typeRef is FirResolvedTypeRef) {
arrayType.getArrayElementType(irBuiltIns)
} else {
// TODO: The element type should be the least upper bound of all arguments' types, e.g., ["4", 2u, 0.42f] => Array<Any>
// Currently, the type of elements in array literals still has integer literal type, which shouldn't be at this stage.
// elementType = arrayOfCall.arguments.map { it.typeRef.toIrType() }.commonSupertype(irBuiltIns)
elementType = arrayOfCall.arguments.firstOrNull()?.typeRef?.toIrType() ?: createErrorType()
arrayType = elementType.toArrayOrPrimitiveArrayType(irBuiltIns)
createErrorType()
}
IrVarargImpl(
startOffset, endOffset,
@@ -311,6 +311,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/annotations/resolveWithLowPriorityAnnotation.kt");
}
@Test
@TestMetadata("resolvedReturnTypeForJavaEnumEntryAfterDeserialization.kt")
public void testResolvedReturnTypeForJavaEnumEntryAfterDeserialization() throws Exception {
runTest("compiler/testData/codegen/box/annotations/resolvedReturnTypeForJavaEnumEntryAfterDeserialization.kt");
}
@Test
@TestMetadata("retentionInJava.kt")
public void testRetentionInJava() throws Exception {
@@ -26,7 +26,6 @@ import org.jetbrains.kotlin.fir.declarations.builder.buildTypeParameter
import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusImpl
import org.jetbrains.kotlin.fir.declarations.utils.effectiveVisibility
import org.jetbrains.kotlin.fir.declarations.utils.modality
import org.jetbrains.kotlin.fir.deserialization.ModuleDataProvider
import org.jetbrains.kotlin.fir.expressions.FirConstExpression
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.classId
@@ -47,7 +46,6 @@ import org.jetbrains.kotlin.load.java.JavaClassFinder
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
import org.jetbrains.kotlin.load.java.structure.*
import org.jetbrains.kotlin.load.java.structure.impl.JavaElementImpl
import org.jetbrains.kotlin.load.java.structure.impl.classFiles.BinaryJavaClass
import org.jetbrains.kotlin.name.*
import org.jetbrains.kotlin.toKtPsiSourceElement
import org.jetbrains.kotlin.types.Variance.INVARIANT
@@ -18,11 +18,9 @@ import org.jetbrains.kotlin.fir.resolve.providers.getClassDeclaredPropertySymbol
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.fir.types.constructClassType
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.load.kotlin.KotlinClassFinder
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass
@@ -48,9 +46,12 @@ internal class AnnotationsLoader(private val session: FirSession, private val ko
}
private fun ClassLiteralValue.toFirClassReferenceExpression(): FirClassReferenceExpression {
val literalLookupTag = ConeClassLikeLookupTagImpl(classId)
val resolvedClassTypeRef = ConeClassLikeLookupTagImpl(classId).toDefaultResolvedTypeRef()
return buildClassReferenceExpression {
classTypeRef = literalLookupTag.toDefaultResolvedTypeRef()
classTypeRef = resolvedClassTypeRef
typeRef = buildResolvedTypeRef {
type = StandardClassIds.KClass.constructClassLikeType(arrayOf(resolvedClassTypeRef.type), false)
}
}
}
@@ -77,13 +78,23 @@ internal class AnnotationsLoader(private val session: FirSession, private val ko
}
}
}
typeRef = buildResolvedTypeRef {
type = ConeClassLikeTypeImpl(
ConeClassLikeLookupTagImpl(this@toEnumEntryReferenceExpression),
emptyArray(),
isNullable = false
)
}
}
}
override fun visitClassLiteral(name: Name?, value: ClassLiteralValue) {
if (name == null) return
argumentMap[name] = buildGetClassCall {
argumentList = buildUnaryArgumentList(value.toFirClassReferenceExpression())
val argument = value.toFirClassReferenceExpression()
argumentList = buildUnaryArgumentList(argument)
typeRef = argument.typeRef
}
}
@@ -108,7 +119,9 @@ internal class AnnotationsLoader(private val session: FirSession, private val ko
override fun visitClassLiteral(value: ClassLiteralValue) {
elements.add(
buildGetClassCall {
argumentList = buildUnaryArgumentList(value.toFirClassReferenceExpression())
val argument = value.toFirClassReferenceExpression()
argumentList = buildUnaryArgumentList(argument)
typeRef = argument.typeRef
}
)
}
@@ -12,10 +12,7 @@ import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
import org.jetbrains.kotlin.fir.expressions.buildUnaryArgumentList
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.builder.*
import org.jetbrains.kotlin.fir.java.declarations.buildJavaValueParameter
import org.jetbrains.kotlin.fir.references.builder.buildErrorNamedReference
@@ -86,11 +83,17 @@ internal fun JavaAnnotationArgument.toFirExpression(
}
is JavaEnumValueAnnotationArgument -> buildEnumCall(session, enumClassId, entryName)
is JavaClassObjectAnnotationArgument -> buildGetClassCall {
val resolvedClassTypeRef = getReferencedType().toFirResolvedTypeRef(session, javaTypeParameterStack)
val resolvedTypeRef = buildResolvedTypeRef {
type = StandardClassIds.KClass.constructClassLikeType(arrayOf(resolvedClassTypeRef.type), false)
}
argumentList = buildUnaryArgumentList(
buildClassReferenceExpression {
classTypeRef = getReferencedType().toFirResolvedTypeRef(session, javaTypeParameterStack)
classTypeRef = resolvedClassTypeRef
typeRef = resolvedTypeRef
}
)
typeRef = resolvedTypeRef
}
is JavaAnnotationAsAnnotationArgument -> getAnnotation().toFirAnnotationCall(session, javaTypeParameterStack)
else -> buildErrorExpression {
@@ -133,6 +136,16 @@ private fun buildEnumCall(session: FirSession, classId: ClassId?, entryName: Nam
this.calleeReference = calleeReference ?: buildErrorNamedReference {
diagnostic = ConeSimpleDiagnostic("Strange Java enum value: $classId.$entryName", DiagnosticKind.Java)
}
if (classId != null) {
this.typeRef = buildResolvedTypeRef {
type = ConeClassLikeTypeImpl(
ConeClassLikeLookupTagImpl(classId),
emptyArray(),
isNullable = false
)
}
}
}
}
@@ -37,7 +37,6 @@ internal class FirArrayOfCallTransformer : FirDefaultTransformer<Nothing?>() {
if (!functionCall.isArrayOfCall) {
return null
}
val typeRef = functionCall.typeRef
return buildArrayOfCall {
source = functionCall.source
annotations += functionCall.annotations
@@ -49,8 +48,7 @@ internal class FirArrayOfCallTransformer : FirDefaultTransformer<Nothing?>() {
}
}
}
}.apply {
replaceTypeRef(typeRef)
typeRef = functionCall.typeRef
}
}
@@ -25,24 +25,19 @@ import org.jetbrains.kotlin.fir.visitors.*
@FirBuilderDsl
class FirClassReferenceExpressionBuilder : FirAnnotationContainerBuilder, FirExpressionBuilder {
override var source: KtSourceElement? = null
override var typeRef: FirTypeRef = FirImplicitTypeRefImpl(null)
override val annotations: MutableList<FirAnnotation> = mutableListOf()
lateinit var classTypeRef: FirTypeRef
override fun build(): FirClassReferenceExpression {
return FirClassReferenceExpressionImpl(
source,
typeRef,
annotations,
classTypeRef,
)
}
@Deprecated("Modification of 'typeRef' has no impact for FirClassReferenceExpressionBuilder", level = DeprecationLevel.HIDDEN)
override var typeRef: FirTypeRef
get() = throw IllegalStateException()
set(_) {
throw IllegalStateException()
}
}
@OptIn(ExperimentalContracts::class)
@@ -28,24 +28,19 @@ import org.jetbrains.kotlin.fir.visitors.*
@FirBuilderDsl
class FirGetClassCallBuilder : FirCallBuilder, FirAnnotationContainerBuilder, FirExpressionBuilder {
override var source: KtSourceElement? = null
override var typeRef: FirTypeRef = FirImplicitTypeRefImpl(null)
override val annotations: MutableList<FirAnnotation> = mutableListOf()
override lateinit var argumentList: FirArgumentList
override fun build(): FirGetClassCall {
return FirGetClassCallImpl(
source,
typeRef,
annotations,
argumentList,
)
}
@Deprecated("Modification of 'typeRef' has no impact for FirGetClassCallBuilder", level = DeprecationLevel.HIDDEN)
override var typeRef: FirTypeRef
get() = throw IllegalStateException()
set(_) {
throw IllegalStateException()
}
}
@OptIn(ExperimentalContracts::class)
@@ -9,7 +9,6 @@ import org.jetbrains.kotlin.KtSourceElement
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
import org.jetbrains.kotlin.fir.expressions.FirClassReferenceExpression
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.types.impl.FirImplicitTypeRefImpl
import org.jetbrains.kotlin.fir.visitors.*
/*
@@ -19,11 +18,10 @@ import org.jetbrains.kotlin.fir.visitors.*
internal class FirClassReferenceExpressionImpl(
override val source: KtSourceElement?,
override var typeRef: FirTypeRef,
override val annotations: MutableList<FirAnnotation>,
override var classTypeRef: FirTypeRef,
) : FirClassReferenceExpression() {
override var typeRef: FirTypeRef = FirImplicitTypeRefImpl(null)
override fun <R, D> acceptChildren(visitor: FirVisitor<R, D>, data: D) {
typeRef.accept(visitor, data)
annotations.forEach { it.accept(visitor, data) }
@@ -11,7 +11,6 @@ import org.jetbrains.kotlin.fir.expressions.FirArgumentList
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.FirGetClassCall
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.types.impl.FirImplicitTypeRefImpl
import org.jetbrains.kotlin.fir.visitors.*
/*
@@ -21,10 +20,10 @@ import org.jetbrains.kotlin.fir.visitors.*
internal class FirGetClassCallImpl(
override val source: KtSourceElement?,
override var typeRef: FirTypeRef,
override val annotations: MutableList<FirAnnotation>,
override var argumentList: FirArgumentList,
) : FirGetClassCall() {
override var typeRef: FirTypeRef = FirImplicitTypeRefImpl(null)
override val argument: FirExpression get() = argumentList.arguments.first()
override fun <R, D> acceptChildren(visitor: FirVisitor<R, D>, data: D) {
@@ -366,7 +366,9 @@ object BuilderConfigurator : AbstractBuilderConfigurator<FirTreeBuilder>(FirTree
varargArgumentsExpression,
checkedSafeCallSubject,
safeCallExpression,
arrayOfCall
arrayOfCall,
classReferenceExpression,
getClassCall
)
elementsWithDefaultTypeRef.forEach {
val (element, name) = when (it) {
@@ -561,6 +561,8 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
"FirArrayOfCallImpl",
"FirIntegerLiteralOperatorCallImpl",
"FirContextReceiverImpl",
"FirClassReferenceExpressionImpl",
"FirGetClassCallImpl"
)
configureFieldInAllImplementations(
field = "typeRef",
@@ -0,0 +1,43 @@
// TARGET_BACKEND: JVM
// MODULE: lib
// FILE: Enum.java
public enum Enum {
Value
}
// FILE: C.java
public class C {
}
// FILE: ArgumentsSource.java
public @interface ArgumentsSource {
Class<?> value();
}
// FILE: MethodSource.java
@ArgumentsSource(C.class)
public @interface MethodSource {
String[] value() default "";
}
// FILE: test.kt
import Enum
annotation class Ann(val e: Enum)
@Ann(Enum.Value) // Checking Java enchancement after deserialization
@MethodSource("getTestFiles")
fun test(): String {
return "OK"
}
// MODULE: main(lib)
// FILE: main.kt
@MethodSource("getTestFiles")
fun box(): String {
return test()
}
@@ -255,8 +255,8 @@ FILE fqName:<root> fileName:/C.kt
Annos(value = Anno(token = 'OK'))
Strings(value = 'OK')
Ints(value = '42')
Enums(value = GET_ENUM 'ENUM_ENTRY name:EA' type=IrErrorType(null))
Classes(value = CLASS_REFERENCE 'CLASS IR_EXTERNAL_DECLARATION_STUB CLASS name:Double modality:FINAL visibility:public superTypes:[kotlin.Number; kotlin.Comparable<kotlin.Double>; java.io.Serializable]' type=IrErrorType(null))
Enums(value = GET_ENUM 'ENUM_ENTRY name:EA' type=<root>.E)
Classes(value = CLASS_REFERENCE 'CLASS IR_EXTERNAL_DECLARATION_STUB CLASS name:Double modality:FINAL visibility:public superTypes:[kotlin.Number; kotlin.Comparable<kotlin.Double>; java.io.Serializable]' type=kotlin.reflect.KClass<kotlin.Double>)
overridden:
public open fun test (): kotlin.Unit declared in <root>.A
$this: VALUE_PARAMETER name:<this> type:<root>.A
@@ -293,6 +293,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/annotations/resolveWithLowPriorityAnnotation.kt");
}
@Test
@TestMetadata("resolvedReturnTypeForJavaEnumEntryAfterDeserialization.kt")
public void testResolvedReturnTypeForJavaEnumEntryAfterDeserialization() throws Exception {
runTest("compiler/testData/codegen/box/annotations/resolvedReturnTypeForJavaEnumEntryAfterDeserialization.kt");
}
@Test
@TestMetadata("retentionInJava.kt")
public void testRetentionInJava() throws Exception {
@@ -311,6 +311,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/annotations/resolveWithLowPriorityAnnotation.kt");
}
@Test
@TestMetadata("resolvedReturnTypeForJavaEnumEntryAfterDeserialization.kt")
public void testResolvedReturnTypeForJavaEnumEntryAfterDeserialization() throws Exception {
runTest("compiler/testData/codegen/box/annotations/resolvedReturnTypeForJavaEnumEntryAfterDeserialization.kt");
}
@Test
@TestMetadata("retentionInJava.kt")
public void testRetentionInJava() throws Exception {
@@ -258,6 +258,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/annotations/resolveWithLowPriorityAnnotation.kt");
}
@TestMetadata("resolvedReturnTypeForJavaEnumEntryAfterDeserialization.kt")
public void testResolvedReturnTypeForJavaEnumEntryAfterDeserialization() throws Exception {
runTest("compiler/testData/codegen/box/annotations/resolvedReturnTypeForJavaEnumEntryAfterDeserialization.kt");
}
@TestMetadata("retentionInJava.kt")
public void testRetentionInJava() throws Exception {
runTest("compiler/testData/codegen/box/annotations/retentionInJava.kt");