[FIR] Fix serialization of empty varargs in annotations in KLIBs
#KT-59249 Fixed
This commit is contained in:
committed by
Space Team
parent
487c3e80bb
commit
38a54549ff
+1
-1
@@ -147,7 +147,7 @@ abstract class AbstractLoadedMetadataDumpHandler<A : ResultingArtifact.Binary<A>
|
||||
}
|
||||
|
||||
val emptyModule = TestModule(
|
||||
name = "empty", module.targetPlatform, module.targetBackend, FrontendKinds.FIR,
|
||||
name = "dump-${module.name}", module.targetPlatform, module.targetBackend, FrontendKinds.FIR,
|
||||
BackendKinds.IrBackend, module.binaryKind, files = emptyList(),
|
||||
allDependencies = listOf(DependencyDescription(module.name, dependencyKind, DependencyRelation.RegularDependency)),
|
||||
RegisteredDirectives.Empty, languageVersionSettings
|
||||
|
||||
+21
-12
@@ -6,15 +6,14 @@
|
||||
package org.jetbrains.kotlin.fir.serialization.constant
|
||||
|
||||
import org.jetbrains.kotlin.config.AnalysisFlags
|
||||
import org.jetbrains.kotlin.constant.AnnotationValue
|
||||
import org.jetbrains.kotlin.constant.ConstantValue
|
||||
import org.jetbrains.kotlin.constant.ErrorValue
|
||||
import org.jetbrains.kotlin.constant.KClassValue
|
||||
import org.jetbrains.kotlin.constant.*
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
|
||||
import org.jetbrains.kotlin.fir.declarations.itOrExpectHasDefaultParameterValue
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
import org.jetbrains.kotlin.fir.languageVersionSettings
|
||||
import org.jetbrains.kotlin.fir.render
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
||||
@@ -22,24 +21,34 @@ import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
||||
internal fun Map<Name, FirExpression>.convertToConstantValues(
|
||||
session: FirSession,
|
||||
constValueProvider: ConstValueProvider?
|
||||
): Map<Name, ConstantValue<*>> {
|
||||
return this.map { (name, firExpression) ->
|
||||
val constantValue = constValueProvider?.findConstantValueFor(firExpression)
|
||||
): MutableMap<Name, ConstantValue<*>> {
|
||||
return this.mapValuesTo(mutableMapOf()) { (_, firExpression) ->
|
||||
constValueProvider?.findConstantValueFor(firExpression)
|
||||
?: firExpression.toConstantValue(session, constValueProvider)
|
||||
?: runIf(session.languageVersionSettings.getFlag(AnalysisFlags.metadataCompilation)) {
|
||||
ErrorValue.ErrorValueWithMessage("Constant conversion can be ignored in metadata compilation mode")
|
||||
}
|
||||
?: error("Cannot convert expression ${firExpression.render()} to constant")
|
||||
name to constantValue
|
||||
}.toMap()
|
||||
}
|
||||
}
|
||||
|
||||
internal fun MutableMap<Name, ConstantValue<Any?>>.addEmptyVarargValuesFor(
|
||||
symbol: FirFunctionSymbol<*>?,
|
||||
): MutableMap<Name, ConstantValue<Any?>> = apply {
|
||||
if (symbol == null) return@apply
|
||||
for ((i, parameter) in symbol.valueParameterSymbols.withIndex()) {
|
||||
if (parameter.name !in this && parameter.isVararg && !symbol.fir.itOrExpectHasDefaultParameterValue(i)) {
|
||||
this[parameter.name] = ArrayValue(emptyList())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun LinkedHashMap<FirExpression, FirValueParameter>.convertToConstantValues(
|
||||
session: FirSession,
|
||||
constValueProvider: ConstValueProvider?,
|
||||
): Map<Name, ConstantValue<*>> {
|
||||
return this.map { (firExpression, firValueParameter) -> firValueParameter.name to firExpression }
|
||||
.toMap().convertToConstantValues(session, constValueProvider)
|
||||
): MutableMap<Name, ConstantValue<*>> {
|
||||
return this.entries.associate { (firExpression, firValueParameter) -> firValueParameter.name to firExpression }
|
||||
.convertToConstantValues(session, constValueProvider)
|
||||
}
|
||||
|
||||
inline fun <reified T : ConeKotlinType> AnnotationValue.coneTypeSafe(): T? {
|
||||
|
||||
+10
-3
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.fir.declarations.FirField
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isConst
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isFinal
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.references.toResolvedFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.render
|
||||
import org.jetbrains.kotlin.fir.resolve.toFirRegularClassSymbol
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirArrayOfCallTransformer
|
||||
@@ -101,9 +102,12 @@ internal object FirToConstantValueTransformer : FirDefaultVisitor<ConstantValue<
|
||||
|
||||
override fun visitAnnotation(
|
||||
annotation: FirAnnotation,
|
||||
data: FirToConstantValueTransformerData
|
||||
data: FirToConstantValueTransformerData,
|
||||
): ConstantValue<*> {
|
||||
val mapping = annotation.argumentMapping.mapping.convertToConstantValues(data.session, data.constValueProvider)
|
||||
val mapping = annotation.argumentMapping.mapping.convertToConstantValues(
|
||||
data.session,
|
||||
data.constValueProvider
|
||||
).addEmptyVarargValuesFor(annotation.toReference()?.toResolvedFunctionSymbol())
|
||||
return AnnotationValue.create(annotation.annotationTypeRef.coneType, mapping)
|
||||
}
|
||||
|
||||
@@ -149,7 +153,10 @@ internal object FirToConstantValueTransformer : FirDefaultVisitor<ConstantValue<
|
||||
if (constructedClassSymbol.classKind != ClassKind.ANNOTATION_CLASS) return null
|
||||
|
||||
val mapping = constructorCall.resolvedArgumentMapping
|
||||
?.convertToConstantValues(data.session, data.constValueProvider)
|
||||
?.convertToConstantValues(
|
||||
data.session,
|
||||
data.constValueProvider
|
||||
)?.addEmptyVarargValuesFor(symbol)
|
||||
?: return null
|
||||
return AnnotationValue.create(qualifiedAccessExpression.typeRef.coneType, mapping)
|
||||
}
|
||||
|
||||
@@ -48,6 +48,10 @@ fun FirReference.toResolvedValueParameterSymbol(discardErrorReference: Boolean =
|
||||
return this.toResolvedSymbol<FirValueParameterSymbol>(discardErrorReference)
|
||||
}
|
||||
|
||||
fun FirReference.toResolvedFunctionSymbol(discardErrorReference: Boolean = false): FirFunctionSymbol<*>? {
|
||||
return this.toResolvedSymbol<FirFunctionSymbol<*>>(discardErrorReference)
|
||||
}
|
||||
|
||||
fun FirReference.toResolvedNamedFunctionSymbol(discardErrorReference: Boolean = false): FirNamedFunctionSymbol? {
|
||||
return this.toResolvedSymbol<FirNamedFunctionSymbol>(discardErrorReference)
|
||||
}
|
||||
|
||||
+42
-1
@@ -1,7 +1,9 @@
|
||||
Module: common
|
||||
Module: platform
|
||||
field:@FIELD:R|test/Anno|(t = <implicitArrayOf>(String(prosper))) public final val bar: R|kotlin/Int|
|
||||
public get(): R|kotlin/Int|
|
||||
|
||||
@R|test/Anno|(t = <implicitArrayOf>()) public final fun baz(): R|kotlin/Unit|
|
||||
@R|test/Anno|(t = <implicitArrayOf>()) @R|test/Anno2|() @R|test/Anno3|() @R|test/Anno4|(t = <implicitArrayOf>()) @R|test/Anno5|(t = <implicitArrayOf>()) @R|test/Anno6|(t = <implicitArrayOf>()) public final fun baz(): R|kotlin/Unit|
|
||||
|
||||
@R|test/Anno|(t = <implicitArrayOf>(String(live), String(long))) public final fun foo(): R|kotlin/Unit|
|
||||
|
||||
@@ -13,3 +15,42 @@ public final annotation class Anno : R|kotlin/Annotation| {
|
||||
|
||||
}
|
||||
|
||||
public final annotation class Anno2 : R|kotlin/Annotation| {
|
||||
public final val t: R|kotlin/Array<out kotlin/String>| = <implicitArrayOf>()
|
||||
public get(): R|kotlin/Array<out kotlin/String>|
|
||||
|
||||
public constructor(vararg t: R|kotlin/Array<out kotlin/String>| = STUB): R|test/Anno2|
|
||||
|
||||
}
|
||||
|
||||
public final annotation class Anno3 : R|kotlin/Annotation| {
|
||||
public final val t: R|kotlin/Array<out kotlin/String>| = <implicitArrayOf>(String(a))
|
||||
public get(): R|kotlin/Array<out kotlin/String>|
|
||||
|
||||
public constructor(vararg t: R|kotlin/Array<out kotlin/String>| = STUB): R|test/Anno3|
|
||||
|
||||
}
|
||||
|
||||
public final annotation class Anno4 : R|kotlin/Annotation| {
|
||||
public final val t: R|kotlin/Array<out kotlin/String>|
|
||||
public get(): R|kotlin/Array<out kotlin/String>|
|
||||
|
||||
public constructor(vararg t: R|kotlin/Array<out kotlin/String>|): R|test/Anno4|
|
||||
|
||||
}
|
||||
|
||||
public final annotation class Anno5 : R|kotlin/Annotation| {
|
||||
public final val t: R|kotlin/Array<out kotlin/String>| = <implicitArrayOf>()
|
||||
public get(): R|kotlin/Array<out kotlin/String>|
|
||||
|
||||
public constructor(vararg t: R|kotlin/Array<out kotlin/String>| = STUB): R|test/Anno5|
|
||||
|
||||
}
|
||||
|
||||
public final annotation class Anno6 : R|kotlin/Annotation| {
|
||||
public final val t: R|kotlin/Array<out kotlin/String>| = <implicitArrayOf>(String(a))
|
||||
public get(): R|kotlin/Array<out kotlin/String>|
|
||||
|
||||
public constructor(vararg t: R|kotlin/Array<out kotlin/String>| = STUB): R|test/Anno6|
|
||||
|
||||
}
|
||||
|
||||
+40
-1
@@ -1,7 +1,7 @@
|
||||
field:@FIELD:R|test/Anno|(t = <implicitArrayOf>(String(prosper))) public final val bar: R|kotlin/Int|
|
||||
public get(): R|kotlin/Int|
|
||||
|
||||
@R|test/Anno|(t = <implicitArrayOf>()) public final fun baz(): R|kotlin/Unit|
|
||||
@R|test/Anno|(t = <implicitArrayOf>()) @R|test/Anno2|() @R|test/Anno3|() @R|test/Anno4|(t = <implicitArrayOf>()) @R|test/Anno5|() @R|test/Anno6|() public final fun baz(): R|kotlin/Unit|
|
||||
|
||||
@R|test/Anno|(t = <implicitArrayOf>(String(live), String(long))) public final fun foo(): R|kotlin/Unit|
|
||||
|
||||
@@ -13,3 +13,42 @@ public final annotation class Anno : R|kotlin/Annotation| {
|
||||
|
||||
}
|
||||
|
||||
public final annotation class Anno2 : R|kotlin/Annotation| {
|
||||
public final val t: R|kotlin/Array<out kotlin/String>| = <implicitArrayOf>()
|
||||
public get(): R|kotlin/Array<out kotlin/String>|
|
||||
|
||||
public constructor(vararg t: R|kotlin/Array<out kotlin/String>| = STUB): R|test/Anno2|
|
||||
|
||||
}
|
||||
|
||||
public final annotation class Anno3 : R|kotlin/Annotation| {
|
||||
public final val t: R|kotlin/Array<out kotlin/String>| = <implicitArrayOf>(String(a))
|
||||
public get(): R|kotlin/Array<out kotlin/String>|
|
||||
|
||||
public constructor(vararg t: R|kotlin/Array<out kotlin/String>| = STUB): R|test/Anno3|
|
||||
|
||||
}
|
||||
|
||||
public final annotation class Anno4 : R|kotlin/Annotation| {
|
||||
public final val t: R|kotlin/Array<out kotlin/String>|
|
||||
public get(): R|kotlin/Array<out kotlin/String>|
|
||||
|
||||
public constructor(vararg t: R|kotlin/Array<out kotlin/String>|): R|test/Anno4|
|
||||
|
||||
}
|
||||
|
||||
public final annotation class Anno5 : R|kotlin/Annotation| {
|
||||
public final val t: R|kotlin/Array<out kotlin/String>| = <implicitArrayOf>()
|
||||
public get(): R|kotlin/Array<out kotlin/String>|
|
||||
|
||||
public constructor(vararg t: R|kotlin/Array<out kotlin/String>| = STUB): R|test/Anno5|
|
||||
|
||||
}
|
||||
|
||||
public final annotation class Anno6 : R|kotlin/Annotation| {
|
||||
public final val t: R|kotlin/Array<out kotlin/String>| = <implicitArrayOf>(String(a))
|
||||
public get(): R|kotlin/Array<out kotlin/String>|
|
||||
|
||||
public constructor(vararg t: R|kotlin/Array<out kotlin/String>| = STUB): R|test/Anno6|
|
||||
|
||||
}
|
||||
|
||||
+41
-1
@@ -1,7 +1,7 @@
|
||||
public final val bar: R|kotlin/Int|
|
||||
public get(): R|kotlin/Int|
|
||||
|
||||
@R|test/Anno|() public final fun baz(): R|kotlin/Unit|
|
||||
@R|test/Anno|(t = <implicitArrayOf>()) @R|test/Anno2|() @R|test/Anno3|() @R|test/Anno4|(t = <implicitArrayOf>()) @R|test/Anno5|() @R|test/Anno6|() public final fun baz(): R|kotlin/Unit|
|
||||
|
||||
@R|test/Anno|(t = <implicitArrayOf>(String(live), String(long))) public final fun foo(): R|kotlin/Unit|
|
||||
|
||||
@@ -12,3 +12,43 @@ public final annotation class Anno : R|kotlin/Annotation| {
|
||||
public constructor(vararg t: R|kotlin/Array<out kotlin/String>|): R|test/Anno|
|
||||
|
||||
}
|
||||
|
||||
public final annotation class Anno2 : R|kotlin/Annotation| {
|
||||
public final val t: R|kotlin/Array<out kotlin/String>|
|
||||
public get(): R|kotlin/Array<out kotlin/String>|
|
||||
|
||||
public constructor(vararg t: R|kotlin/Array<out kotlin/String>| = STUB): R|test/Anno2|
|
||||
|
||||
}
|
||||
|
||||
public final annotation class Anno3 : R|kotlin/Annotation| {
|
||||
public final val t: R|kotlin/Array<out kotlin/String>|
|
||||
public get(): R|kotlin/Array<out kotlin/String>|
|
||||
|
||||
public constructor(vararg t: R|kotlin/Array<out kotlin/String>| = STUB): R|test/Anno3|
|
||||
|
||||
}
|
||||
|
||||
public final annotation class Anno4 : R|kotlin/Annotation| {
|
||||
public final val t: R|kotlin/Array<out kotlin/String>|
|
||||
public get(): R|kotlin/Array<out kotlin/String>|
|
||||
|
||||
public constructor(vararg t: R|kotlin/Array<out kotlin/String>|): R|test/Anno4|
|
||||
|
||||
}
|
||||
|
||||
public final annotation class Anno5 : R|kotlin/Annotation| {
|
||||
public final val t: R|kotlin/Array<out kotlin/String>|
|
||||
public get(): R|kotlin/Array<out kotlin/String>|
|
||||
|
||||
public constructor(vararg t: R|kotlin/Array<out kotlin/String>| = STUB): R|test/Anno5|
|
||||
|
||||
}
|
||||
|
||||
public final annotation class Anno6 : R|kotlin/Annotation| {
|
||||
public final val t: R|kotlin/Array<out kotlin/String>|
|
||||
public get(): R|kotlin/Array<out kotlin/String>|
|
||||
|
||||
public constructor(vararg t: R|kotlin/Array<out kotlin/String>| = STUB): R|test/Anno6|
|
||||
|
||||
}
|
||||
|
||||
Vendored
+24
-2
@@ -1,11 +1,33 @@
|
||||
// PLATFORM_DEPENDANT_METADATA
|
||||
//ALLOW_AST_ACCESS
|
||||
// ALLOW_AST_ACCESS
|
||||
// NO_CHECK_SOURCE_VS_BINARY
|
||||
// IGNORE_BACKEND_K1: JVM_IR, ANY
|
||||
// LANGUAGE: +MultiPlatformProjects
|
||||
// IGNORE K1
|
||||
// ^mute KotlinpCompilerTestDataTest
|
||||
// K1/K2 difference: KT-60820
|
||||
|
||||
// MODULE: common
|
||||
// FILE: common.kt
|
||||
package test
|
||||
|
||||
expect annotation class Anno4(vararg val t: String)
|
||||
expect annotation class Anno5(vararg val t: String = [])
|
||||
expect annotation class Anno6(vararg val t: String = ["a"])
|
||||
|
||||
// MODULE: platform()()(common)
|
||||
// FILE: test.kt
|
||||
package test
|
||||
|
||||
annotation class Anno(vararg val t: String)
|
||||
annotation class Anno2(vararg val t: String = [])
|
||||
annotation class Anno3(vararg val t: String = ["a"])
|
||||
actual annotation class Anno4(vararg val t: String)
|
||||
actual annotation class Anno5(vararg val t: String)
|
||||
actual annotation class Anno6(vararg val t: String)
|
||||
|
||||
@Anno("live", "long") fun foo() {}
|
||||
|
||||
@field:Anno("prosper") val bar = { 42 }()
|
||||
|
||||
@Anno() fun baz() {}
|
||||
@Anno() @Anno2() @Anno3() @Anno4() @Anno5() @Anno6() fun baz() {}
|
||||
|
||||
Vendored
-12
@@ -1,12 +0,0 @@
|
||||
package test
|
||||
|
||||
@field:test.Anno(t = {"prosper"}) public val bar: kotlin.Int
|
||||
public fun `<get-bar>`(): kotlin.Int
|
||||
@test.Anno(t = {}) public fun baz(): kotlin.Unit
|
||||
@test.Anno(t = {"live", "long"}) public fun foo(): kotlin.Unit
|
||||
|
||||
public final annotation class Anno : kotlin.Annotation {
|
||||
/*primary*/ public constructor Anno(/*0*/ vararg t: kotlin.String /*kotlin.Array<out kotlin.String>*/)
|
||||
public final val t: kotlin.Array<out kotlin.String>
|
||||
public final fun `<get-t>`(): kotlin.Array<out kotlin.String>
|
||||
}
|
||||
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.test.util.KtTestUtil
|
||||
import java.io.File
|
||||
import kotlin.test.fail
|
||||
|
||||
private const val IGNORE_K1_DIRECTIVE = "// IGNORE K1"
|
||||
private const val IGNORE_K2_DIRECTIVE = "// IGNORE K2"
|
||||
|
||||
fun compareAllFiles(
|
||||
@@ -37,15 +38,16 @@ fun compareAllFiles(
|
||||
readWriteAndCompare: Boolean,
|
||||
useK2: Boolean,
|
||||
) {
|
||||
val isMutedForK2 = useK2 && InTextDirectivesUtils.findStringWithPrefixes(file.readText(), IGNORE_K2_DIRECTIVE) != null
|
||||
val directive = if (useK2) IGNORE_K2_DIRECTIVE else IGNORE_K1_DIRECTIVE
|
||||
val isMuted = InTextDirectivesUtils.findStringWithPrefixes(file.readText(), directive) != null
|
||||
try {
|
||||
compileAndPrintAllFiles(file, disposable, tmpdir, compareWithTxt, readWriteAndCompare, useK2)
|
||||
} catch (e: Throwable) {
|
||||
if (isMutedForK2) return
|
||||
if (isMuted) return
|
||||
throw e
|
||||
}
|
||||
if (isMutedForK2) {
|
||||
throw AssertionError("Looks like this test can be unmuted. Remove the \"$IGNORE_K2_DIRECTIVE\" directive.")
|
||||
if (isMuted) {
|
||||
throw AssertionError("Looks like this test can be unmuted. Remove the \"$directive\" directive.")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user