[K2] Instantiation of annotations having default values for properties

This commit adds missing pieces for the puzzle:

Annotation instantiation feature uses IrProperty's initializer to instantiate
properties from other modules that have default values which weren't
specified on call site.

To support this feature properly, Fir2IrVisitor should fill LazyIrProperty's
backing field initializer with information from Fir.

To get this information into Fir, FirMemberDeserializer should be able to read
it from KotlinJvmBinaryClass with AnnotationLoaderVisitorImpl. (klibs are unsupported for now)

There's a catch with enum entries references: we can't access session.SymbolProvider to resolve it
because we're still at the deserialization stage, and it can cause StackOverflow if enum is nested in the
same class (see RequiresOptIn.Level). To mitigate this, a new FirEnumEntryDeserializedAccessExpression is produced
instead; it is later replaced with the correct reference in the Fir2IrVisitor.

^KT-58137 Fixed

Also add test to loadJava folder with annotations default values that
verifies metadata loading
This commit is contained in:
Leonid Startsev
2023-04-24 18:32:13 +02:00
committed by Space Team
parent d757847ed6
commit c4255f9a9e
34 changed files with 797 additions and 157 deletions
@@ -164,6 +164,15 @@ abstract class AbstractAnnotationDeserializer(
): List<FirAnnotation> {
return emptyList()
}
open fun loadAnnotationPropertyDefaultValue(
containerSource: DeserializedContainerSource?,
propertyProto: ProtoBuf.Property,
expectedPropertyType: FirTypeRef,
nameResolver: NameResolver,
typeTable: TypeTable
): FirExpression? {
return null
}
abstract fun loadTypeAnnotations(typeProto: ProtoBuf.Type, nameResolver: NameResolver): List<FirAnnotation>
@@ -0,0 +1,51 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.deserialization
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.utils.isStatic
import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
import org.jetbrains.kotlin.fir.expressions.FirEnumEntryDeserializedAccessExpression
import org.jetbrains.kotlin.fir.expressions.FirPropertyAccessExpression
import org.jetbrains.kotlin.fir.expressions.builder.buildPropertyAccessExpression
import org.jetbrains.kotlin.fir.references.builder.buildErrorNamedReference
import org.jetbrains.kotlin.fir.references.builder.buildResolvedNamedReference
import org.jetbrains.kotlin.fir.resolve.providers.getClassDeclaredPropertySymbols
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
import org.jetbrains.kotlin.fir.types.toLookupTag
fun FirEnumEntryDeserializedAccessExpression.toQualifiedPropertyAccessExpression(session: FirSession): FirPropertyAccessExpression =
buildPropertyAccessExpression {
val entryPropertySymbol = session.symbolProvider.getClassDeclaredPropertySymbols(
enumClassId, enumEntryName,
).firstOrNull { it.isStatic }
calleeReference = when {
entryPropertySymbol != null -> {
buildResolvedNamedReference {
this.name = enumEntryName
resolvedSymbol = entryPropertySymbol
}
}
else -> {
buildErrorNamedReference {
diagnostic = ConeSimpleDiagnostic(
"Strange deserialized enum value: $enumClassId.$enumEntryName",
DiagnosticKind.Java,
)
}
}
}
typeRef = buildResolvedTypeRef {
type = ConeClassLikeTypeImpl(
enumClassId.toLookupTag(), emptyArray(), isNullable = false
)
}
}
@@ -448,7 +448,20 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) {
)
}
this.containerSource = c.containerSource
this.initializer = c.constDeserializer.loadConstant(proto, symbol.callableId, c.nameResolver)
this.initializer = when {
Flags.HAS_CONSTANT.get(proto.flags) -> c.constDeserializer.loadConstant(proto, symbol.callableId, c.nameResolver)
// classSymbol?.classKind?.isAnnotationClass throws 'Fir is not initialized for FirRegularClassSymbol kotlin/String'
classProto != null && Flags.CLASS_KIND.get(classProto.flags) == ProtoBuf.Class.Kind.ANNOTATION_CLASS -> {
c.annotationDeserializer.loadAnnotationPropertyDefaultValue(
c.containerSource,
proto,
returnTypeRef,
local.nameResolver,
local.typeTable
)
}
else -> null
}
deprecationsProvider = annotations.getDeprecationsProviderFromAnnotations(c.session, fromJava = false)
proto.contextReceiverTypes(c.typeTable).mapTo(contextReceivers, ::loadContextReceiver)