diff --git a/analysis/analysis-api/testData/components/callResolver/resolveCall/annotationInAnnotation_multipleAnnotations_collectionLiteral.kt b/analysis/analysis-api/testData/components/callResolver/resolveCall/annotationInAnnotation_multipleAnnotations_collectionLiteral.kt
index 6613d1be0f7..a24e24da024 100644
--- a/analysis/analysis-api/testData/components/callResolver/resolveCall/annotationInAnnotation_multipleAnnotations_collectionLiteral.kt
+++ b/analysis/analysis-api/testData/components/callResolver/resolveCall/annotationInAnnotation_multipleAnnotations_collectionLiteral.kt
@@ -2,5 +2,5 @@ annotation class Annotation(vararg val strings: String)
annotation class AnnotationArray(vararg val annos: Annotation)
-@AnnotationArray([Annotation("v1", "v2"), Annotation(["v3", "v4"])])
+@AnnotationArray(annos = [Annotation("v1", "v2"), Annotation(["v3", "v4"])])
class C
diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt
index 200a02125d1..54d2f92b248 100644
--- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt
+++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.ConeStubDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
import org.jetbrains.kotlin.fir.expressions.*
+import org.jetbrains.kotlin.fir.expressions.builder.buildArgumentList
import org.jetbrains.kotlin.fir.expressions.builder.buildResolvedReifiedParameterReference
import org.jetbrains.kotlin.fir.references.*
import org.jetbrains.kotlin.fir.references.builder.buildBackingFieldReference
@@ -37,11 +38,14 @@ import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirExpressions
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.resultType
import org.jetbrains.kotlin.fir.scopes.unsubstitutedScope
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
+import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.*
+import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
import org.jetbrains.kotlin.fir.types.builder.buildStarProjection
import org.jetbrains.kotlin.fir.types.builder.buildTypeProjectionWithVariance
+import org.jetbrains.kotlin.fir.visitors.transformSingle
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
@@ -520,24 +524,40 @@ class FirCallResolver(
fun resolveAnnotationCall(annotation: FirAnnotationCall): FirAnnotationCall? {
val reference = annotation.calleeReference as? FirSimpleNamedReference ?: return null
- annotation.replaceArgumentList(annotation.argumentList.transform(transformer, ResolutionMode.ContextDependent))
-
- val callInfo = CallInfo(
- annotation,
- CallKind.Function,
- name = reference.name,
- explicitReceiver = null,
- annotation.argumentList,
- isImplicitInvoke = false,
- typeArguments = annotation.typeArguments,
- session,
- components.file,
- components.containingDeclarations
- )
-
val annotationClassSymbol = annotation.getCorrespondingClassSymbolOrNull(session)
val resolvedReference = if (annotationClassSymbol != null && annotationClassSymbol.fir.classKind == ClassKind.ANNOTATION_CLASS) {
- val resolutionResult = createCandidateForAnnotationCall(annotationClassSymbol, callInfo)
+ val constructorSymbol = getConstructorSymbol(annotationClassSymbol)
+ constructorSymbol?.lazyResolveToPhase(FirResolvePhase.TYPES)
+
+ if (constructorSymbol != null && annotation.arguments.isNotEmpty()) {
+ // We want to "desugar" array literal arguments whose expected type is not a primitive or unsigned array to
+ // function calls to arrayOf so that we can properly complete them eventually.
+ // In order to find out what the expected type is, we need to run argument mapping.
+ // However, we don't want to resolve them with expectedType because we don't want to force completion before the whole
+ // call is completed so that type variables are preserved.
+ // We therefore use a special resolution mode that triggers array literal desugaring but doesn't force completion.
+ val mapping = transformer.resolutionContext.bodyResolveComponents.mapArguments(
+ annotation.arguments, constructorSymbol.fir, originScope = null, callSiteIsOperatorCall = false,
+ )
+ val argumentsToParameters = mapping.toArgumentToParameterMapping()
+ annotation.replaceArgumentList(buildArgumentList {
+ source = annotation.argumentList.source
+ annotation.arguments.mapTo(arguments) {
+ val isPrimitiveOrUnsignedArrayType =
+ argumentsToParameters[it]?.returnTypeRef?.coneType?.isPrimitiveOrUnsignedArray == true
+ val resolutionMode =
+ if (!isPrimitiveOrUnsignedArrayType) ResolutionMode.ContextDependent.TransformingArrayLiterals else ResolutionMode.ContextDependent.Default
+ it.transformSingle(transformer, resolutionMode)
+ }
+ })
+ } else {
+ annotation.replaceArgumentList(annotation.argumentList.transform(transformer, ResolutionMode.ContextDependent.Default))
+ }
+
+ val callInfo = toCallInfo(annotation, reference)
+
+ val resolutionResult = constructorSymbol
+ ?.let { runResolutionForGivenSymbol(callInfo, it) }
?: ResolutionResult(callInfo, CandidateApplicability.HIDDEN, emptyList())
createResolvedNamedReference(
reference,
@@ -548,6 +568,10 @@ class FirCallResolver(
explicitReceiver = null
)
} else {
+ annotation.replaceArgumentList(annotation.argumentList.transform(transformer, ResolutionMode.ContextDependent.Default))
+
+ val callInfo = toCallInfo(annotation, reference)
+
buildReferenceWithErrorCandidate(
callInfo,
if (annotationClassSymbol != null) ConeIllegalAnnotationError(reference.name)
@@ -562,10 +586,20 @@ class FirCallResolver(
}
}
- private fun createCandidateForAnnotationCall(
- annotationClassSymbol: FirRegularClassSymbol,
- callInfo: CallInfo
- ): ResolutionResult? {
+ private fun toCallInfo(annotation: FirAnnotationCall, reference: FirSimpleNamedReference): CallInfo = CallInfo(
+ annotation,
+ CallKind.Function,
+ name = reference.name,
+ explicitReceiver = null,
+ annotation.argumentList,
+ isImplicitInvoke = false,
+ typeArguments = annotation.typeArguments,
+ session,
+ components.file,
+ components.containingDeclarations
+ )
+
+ private fun getConstructorSymbol(annotationClassSymbol: FirRegularClassSymbol): FirConstructorSymbol? {
var constructorSymbol: FirConstructorSymbol? = null
annotationClassSymbol.fir.unsubstitutedScope(
session,
@@ -577,11 +611,14 @@ class FirCallResolver(
constructorSymbol = it
}
}
- if (constructorSymbol == null) return null
+ return constructorSymbol
+ }
+
+ private fun runResolutionForGivenSymbol(callInfo: CallInfo, symbol: FirBasedSymbol<*>): ResolutionResult {
val candidateFactory = CandidateFactory(transformer.resolutionContext, callInfo)
val candidate = candidateFactory.createCandidate(
callInfo,
- constructorSymbol!!,
+ symbol,
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER,
scope = null
)
diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolutionMode.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolutionMode.kt
index ecdb7c11f80..7d1d7cd7edf 100644
--- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolutionMode.kt
+++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolutionMode.kt
@@ -18,6 +18,11 @@ sealed class ResolutionMode(val forceFullCompletion: Boolean) {
}
data object Delegate : ContextDependent()
+
+ /**
+ * Forces array literals to be transformed to arrayOf calls.
+ */
+ data object TransformingArrayLiterals : ContextDependent()
}
data object ContextIndependent : ResolutionMode(forceFullCompletion = true)
diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt
index 6f68c66ac1e..950c5ac6a6b 100644
--- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt
+++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt
@@ -1637,14 +1637,20 @@ open class FirExpressionsResolveTransformer(transformer: FirAbstractBodyResolveT
override fun transformArrayOfCall(arrayOfCall: FirArrayOfCall, data: ResolutionMode): FirStatement =
whileAnalysing(session, arrayOfCall) {
if (data is ResolutionMode.ContextDependent.Default) {
+ // Argument for primitive array parameter in annotation call or argument in non-annotation call (unsupported).
arrayOfCall.transformChildren(transformer, data)
arrayOfCall
- } else if (data is ResolutionMode.WithExpectedType && !data.expectedTypeRef.coneType.isPrimitiveOrUnsignedArray) {
+ } else if (
+ data is ResolutionMode.WithExpectedType && !data.expectedTypeRef.coneType.isPrimitiveOrUnsignedArray ||
+ data is ResolutionMode.ContextDependent.TransformingArrayLiterals
+ ) {
+ // Default value of Array parameter or argument for Array parameter in annotation call.
arrayOfCall.transformChildren(transformer, ResolutionMode.ContextDependent)
val call = components.syntheticCallGenerator.generateSyntheticArrayOfCall(arrayOfCall, resolutionContext)
callCompleter.completeCall(call, data)
arrayOfCallTransformer.transformFunctionCall(call, session)
} else {
+ // Default value of primitive array parameter or other unsupported usage.
val syntheticIdCall = components.syntheticCallGenerator.generateSyntheticIdCall(arrayOfCall, resolutionContext)
arrayOfCall.transformChildren(transformer, ResolutionMode.ContextDependent)
callCompleter.completeCall(syntheticIdCall, data)
diff --git a/compiler/testData/diagnostics/tests/collectionLiterals/argumentsOfAnnotation.fir.kt b/compiler/testData/diagnostics/tests/collectionLiterals/argumentsOfAnnotation.fir.kt
index 7f72e048a44..64fc9dcfd51 100644
--- a/compiler/testData/diagnostics/tests/collectionLiterals/argumentsOfAnnotation.fir.kt
+++ b/compiler/testData/diagnostics/tests/collectionLiterals/argumentsOfAnnotation.fir.kt
@@ -6,7 +6,7 @@ fun test1() {}
@Foo([], [], [])
fun test2() {}
-@Foo([1f], [' '], [1])
+@Foo([1f], [' '], [1])
fun test3() {}
@Foo(c = [1f], b = [""], a = [1])
@@ -26,3 +26,15 @@ fun test7() {}
@Foo([two], [], [])
fun test8() {}
+
+interface I
+class C : I
+
+annotation class Test1(val x: Int)
+annotation class Test2>(val x: Test1>)
+@Repeatable annotation class Test3(val x: Array>>)
+
+@Test3([Test2>(Test1(40))])
+@Test3([Test2>(Test1(40))])
+@Test3([Test2(Test1(40))])
+fun test9() {}
diff --git a/compiler/testData/diagnostics/tests/collectionLiterals/argumentsOfAnnotation.kt b/compiler/testData/diagnostics/tests/collectionLiterals/argumentsOfAnnotation.kt
index d4736a8b08c..f70aaa788bf 100644
--- a/compiler/testData/diagnostics/tests/collectionLiterals/argumentsOfAnnotation.kt
+++ b/compiler/testData/diagnostics/tests/collectionLiterals/argumentsOfAnnotation.kt
@@ -26,3 +26,15 @@ fun test7() {}
@Foo([two], [], [])
fun test8() {}
+
+interface I
+class C : I
+
+annotation class Test1(val x: Int)
+annotation class Test2>(val x: Test1>)
+@Repeatable annotation class Test3(val x: Array>>)
+
+@Test3([Test2>(Test1(40))])
+@Test3([Test2>(Test1(40))])
+@Test3([Test2(Test1(40))])
+fun test9() {}
diff --git a/compiler/testData/diagnostics/tests/collectionLiterals/argumentsOfAnnotation.txt b/compiler/testData/diagnostics/tests/collectionLiterals/argumentsOfAnnotation.txt
index 1088834eb80..836845c95cd 100644
--- a/compiler/testData/diagnostics/tests/collectionLiterals/argumentsOfAnnotation.txt
+++ b/compiler/testData/diagnostics/tests/collectionLiterals/argumentsOfAnnotation.txt
@@ -10,6 +10,14 @@ public val two: kotlin.Int = 2
@Foo(a = {1}, b = {}, c = {}) public fun test6(): kotlin.Unit
@Foo(a = {3}, b = {}, c = {}) public fun test7(): kotlin.Unit
@Foo(a = {2}, b = {}, c = {}) public fun test8(): kotlin.Unit
+@Test3(x = {Test2(x = Test1(x = 40))}) @Test3(x = {Test2(x = Test1(x = 40))}) @Test3(x = {Test2(x = Test1(x = 40))}) public fun test9(): kotlin.Unit
+
+public final class C*0*/ T> : I {
+ public constructor C*0*/ T>()
+ public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
+ public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
+ public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
+}
public final annotation class Foo : kotlin.Annotation {
public constructor Foo(/*0*/ a: kotlin.IntArray, /*1*/ b: kotlin.Array, /*2*/ c: kotlin.FloatArray)
@@ -20,3 +28,34 @@ public final annotation class Foo : kotlin.Annotation {
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
+
+public interface I*0*/ T> {
+ public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
+ public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
+ public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
+}
+
+public final annotation class Test1*0*/ T> : kotlin.Annotation {
+ public constructor Test1*0*/ T>(/*0*/ x: kotlin.Int)
+ public final val x: kotlin.Int
+ public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
+ public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
+ public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
+}
+
+public final annotation class Test2*0*/ T1, /*1*/ T2 : I> : kotlin.Annotation {
+ public constructor Test2*0*/ T1, /*1*/ T2 : I>(/*0*/ x: Test1>)
+ public final val x: Test1>
+ public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
+ public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
+ public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
+}
+
+@kotlin.annotation.Repeatable public final annotation class Test3 : kotlin.Annotation {
+ public constructor Test3(/*0*/ x: kotlin.Array>>)
+ public final val x: kotlin.Array>>
+ public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
+ public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
+ public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
+}
+
diff --git a/compiler/testData/diagnostics/tests/collectionLiterals/argumentsOfAnnotationWithKClass.fir.kt b/compiler/testData/diagnostics/tests/collectionLiterals/argumentsOfAnnotationWithKClass.fir.kt
index 01392b2f838..67e38045c11 100644
--- a/compiler/testData/diagnostics/tests/collectionLiterals/argumentsOfAnnotationWithKClass.fir.kt
+++ b/compiler/testData/diagnostics/tests/collectionLiterals/argumentsOfAnnotationWithKClass.fir.kt
@@ -20,10 +20,10 @@ fun test3() {}
@Foo([Gen::class])
fun test4() {}
-@Foo([""])
+@Foo([""])
fun test5() {}
-@Foo([Int::class, 1])
+@Foo([Int::class, 1])
fun test6() {}
@Bar
diff --git a/compiler/testData/diagnostics/tests/collectionLiterals/collectionLiteralsWithVarargs.fir.kt b/compiler/testData/diagnostics/tests/collectionLiterals/collectionLiteralsWithVarargs.fir.kt
index 7a695277178..8624cf006c7 100644
--- a/compiler/testData/diagnostics/tests/collectionLiterals/collectionLiteralsWithVarargs.fir.kt
+++ b/compiler/testData/diagnostics/tests/collectionLiterals/collectionLiteralsWithVarargs.fir.kt
@@ -16,7 +16,7 @@ fun test1_0() {}
@Ann1(*["a", "b"])
fun test1_1() {}
-@Ann1(*["a", 1, null])
+@Ann1(*["a", 1, null])
fun test1_2() {}
@Ann2(*[])
@@ -36,5 +36,5 @@ annotation class AnnArray(val a: Array)
@AnnArray(*["/"])
fun testArray() {}
-@Ann1([""])
+@Ann1([""])
fun testVararg() {}
diff --git a/compiler/testData/diagnostics/tests/varargs/assignArrayToVararagInNamedForm_1_3.fir.kt b/compiler/testData/diagnostics/tests/varargs/assignArrayToVararagInNamedForm_1_3.fir.kt
index b8657c339d0..08bca4fbfbe 100644
--- a/compiler/testData/diagnostics/tests/varargs/assignArrayToVararagInNamedForm_1_3.fir.kt
+++ b/compiler/testData/diagnostics/tests/varargs/assignArrayToVararagInNamedForm_1_3.fir.kt
@@ -19,7 +19,7 @@ fun test_fun(s: String, arr: Array) {
}
fun test_ann(s: String, arr: Array) {
- @Ann([""], x = 1)
+ @Ann([""], x = 1)
foo()
@Ann(*[""], x = 1)
foo()
diff --git a/compiler/testData/diagnostics/tests/varargs/assignArrayToVararagInNamedForm_1_4.fir.kt b/compiler/testData/diagnostics/tests/varargs/assignArrayToVararagInNamedForm_1_4.fir.kt
index 248e7dc5432..e56adf14c76 100644
--- a/compiler/testData/diagnostics/tests/varargs/assignArrayToVararagInNamedForm_1_4.fir.kt
+++ b/compiler/testData/diagnostics/tests/varargs/assignArrayToVararagInNamedForm_1_4.fir.kt
@@ -19,7 +19,7 @@ fun test_fun(s: String, arr: Array) {
}
fun test_ann(s: String, arr: Array) {
- @Ann([""], x = 1)
+ @Ann([""], x = 1)
foo()
@Ann(*[""], x = 1)
foo()
diff --git a/compiler/testData/ir/irText/declarations/annotations/genericAnnotationClasses.fir.ir.txt b/compiler/testData/ir/irText/declarations/annotations/genericAnnotationClasses.fir.ir.txt
index c1ed03dd534..332fab1437c 100644
--- a/compiler/testData/ir/irText/declarations/annotations/genericAnnotationClasses.fir.ir.txt
+++ b/compiler/testData/ir/irText/declarations/annotations/genericAnnotationClasses.fir.ir.txt
@@ -222,7 +222,7 @@ FILE fqName:ann fileName:/genericAnnotationClasses.kt
Test1(x = '42')
Test2(x = '38')
Test3>(x = Test1>>(x = '39'))
- Test4(x = [Test3(x = Test1(x = '40')), Test3(x = Test1(x = '50')), Test3(x = Test1(x = '60'))])
+ Test4(x = [Test3>(x = Test1>>(x = '40')), Test3>(x = Test1>>(x = '50')), Test3>(x = Test1>>(x = '60'))])
Test5(xs = [Test3>(x = Test1>>(x = '70')), Test3>(x = Test1>>(x = '80'))])
$this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:ann.CC
CONSTRUCTOR visibility:public <> () returnType:ann.CC [primary]
diff --git a/compiler/testData/ir/irText/declarations/annotations/genericAnnotationClasses.fir.kt.txt b/compiler/testData/ir/irText/declarations/annotations/genericAnnotationClasses.fir.kt.txt
index 4c8fbd072ff..2bfcc0dc06c 100644
--- a/compiler/testData/ir/irText/declarations/annotations/genericAnnotationClasses.fir.kt.txt
+++ b/compiler/testData/ir/irText/declarations/annotations/genericAnnotationClasses.fir.kt.txt
@@ -90,7 +90,7 @@ open annotation class Test5 : Annotation {
@Test1(x = 42)
@Test2(x = 38)
@Test3>(x = Test1>>(x = 39))
-@Test4(x = [Test3(x = Test1(x = 40)), Test3(x = Test1(x = 50)), Test3(x = Test1(x = 60))])
+@Test4(x = [Test3>(x = Test1>>(x = 40)), Test3>(x = Test1>>(x = 50)), Test3>(x = Test1>>(x = 60))])
@Test5(xs = [Test3>(x = Test1>>(x = 70)), Test3>(x = Test1>>(x = 80))])
class CC {
constructor() /* primary */ {
diff --git a/compiler/testData/ir/irText/declarations/annotations/genericAnnotationClasses.kt b/compiler/testData/ir/irText/declarations/annotations/genericAnnotationClasses.kt
index 8b348ec95be..0a77de3fb97 100644
--- a/compiler/testData/ir/irText/declarations/annotations/genericAnnotationClasses.kt
+++ b/compiler/testData/ir/irText/declarations/annotations/genericAnnotationClasses.kt
@@ -1,5 +1,5 @@
// MUTE_SIGNATURE_COMPARISON_K2: ANY
-// ^ KT-54517
+// ^ KT-60136
package ann