diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt index 3add30f2202..2345479f6e1 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt @@ -767,6 +767,7 @@ class Fir2IrVisitor( 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) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirArrayOfCallTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirArrayOfCallTransformer.kt new file mode 100644 index 00000000000..73e0e15c487 --- /dev/null +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirArrayOfCallTransformer.kt @@ -0,0 +1,54 @@ +/* + * Copyright 2010-2020 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.resolve.transformers.body.resolve + +import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration +import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction +import org.jetbrains.kotlin.fir.expressions.* +import org.jetbrains.kotlin.fir.expressions.builder.buildArgumentList +import org.jetbrains.kotlin.fir.expressions.builder.buildArrayOfCall +import org.jetbrains.kotlin.fir.resolve.transformers.getOriginalFunction +import org.jetbrains.kotlin.fir.types.isArrayType + +/** + * A transformer that converts resolved arrayOf() call to [FirArrayOfCall]. + * + * Note that arrayOf() calls only in [FirAnnotationCall] or the default value of annotation constructor are transformed. + */ +internal class FirArrayOfCallTransformer { + private val FirFunctionCall.isArrayOfCall: Boolean + get() { + val function: FirCallableDeclaration<*> = getOriginalFunction() ?: return false + return function is FirSimpleFunction && + // TODO: extend it to other variants, like emptyArray, intArrayOf, floatArrayOf, etc. + function.name.asString() == "arrayOf" && + function.returnTypeRef.isArrayType && + function.valueParameters.size == 1 && function.valueParameters[0].isVararg && + arguments.size == 1 && + function.receiverTypeRef == null + } + + internal fun toArrayOfCall(functionCall: FirFunctionCall): FirArrayOfCall? { + if (!functionCall.isArrayOfCall) { + return null + } + val typeRef = functionCall.typeRef + return buildArrayOfCall { + source = functionCall.source + annotations += functionCall.annotations + // Note that the signature is: arrayOf(vararg element). Hence, unwrapping the original argument list here. + argumentList = buildArgumentList { + if (functionCall.arguments.isNotEmpty()) { + (functionCall.argument as FirVarargArgumentsExpression).arguments.forEach { + arguments += it + } + } + } + }.apply { + replaceTypeRef(typeRef) + } + } +} diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt index 28fe9df5cdb..5c8da73fbf7 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.fir.resolve.transformers.body.resolve +import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirFunctionTarget import org.jetbrains.kotlin.fir.copy @@ -41,6 +42,15 @@ import org.jetbrains.kotlin.name.Name open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransformer) : FirPartialBodyResolveTransformer(transformer) { private var containingClass: FirRegularClass? = null + private inline fun withFirArrayOfCallTransformer(block: () -> T): T { + transformer.expressionsTransformer.enableArrayOfCallTransformation = true + return try { + block() + } finally { + transformer.expressionsTransformer.enableArrayOfCallTransformation = false + } + } + private fun transformDeclarationContent( declaration: FirDeclaration, data: ResolutionMode ): CompositeTransformResult { @@ -506,6 +516,12 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor override fun transformConstructor(constructor: FirConstructor, data: ResolutionMode): CompositeTransformResult { if (implicitTypeOnly) return constructor.compose() + if (constructor.isPrimary && containingClass?.classKind == ClassKind.ANNOTATION_CLASS) { + return withFirArrayOfCallTransformer { + @Suppress("UNCHECKED_CAST") + transformFunction(constructor, data) as CompositeTransformResult + } + } @Suppress("UNCHECKED_CAST") return transformFunction(constructor, data) as CompositeTransformResult } 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 72138cb01fa..dcba5047771 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 @@ -13,9 +13,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.buildErrorExpression -import org.jetbrains.kotlin.fir.expressions.builder.buildFunctionCall -import org.jetbrains.kotlin.fir.expressions.builder.buildVariableAssignment +import org.jetbrains.kotlin.fir.expressions.builder.* import org.jetbrains.kotlin.fir.references.* import org.jetbrains.kotlin.fir.references.builder.buildErrorNamedReference import org.jetbrains.kotlin.fir.references.builder.buildExplicitSuperReference @@ -41,11 +39,22 @@ import org.jetbrains.kotlin.types.Variance class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransformer) : FirPartialBodyResolveTransformer(transformer) { private inline val builtinTypes: BuiltinTypes get() = session.builtinTypes + private val arrayOfCallTransformer = FirArrayOfCallTransformer() + var enableArrayOfCallTransformation = false init { components.callResolver.initTransformer(this) } + private inline fun withFirArrayOfCallTransformer(block: () -> T): T { + enableArrayOfCallTransformation = true + return try { + block() + } finally { + enableArrayOfCallTransformation = false + } + } + override fun transformExpression(expression: FirExpression, data: ResolutionMode): CompositeTransformResult { if (expression.resultType is FirImplicitTypeRef && expression !is FirWrappedExpression) { val type = buildErrorTypeRef { @@ -187,6 +196,13 @@ class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransformer) : } dataFlowAnalyzer.exitFunctionCall(completeInference, callCompleted) + if (callCompleted) { + if (enableArrayOfCallTransformation) { + arrayOfCallTransformer.toArrayOfCall(completeInference)?.let { + return it.compose() + } + } + } return completeInference.compose() } @@ -584,12 +600,14 @@ class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransformer) : override fun transformAnnotationCall(annotationCall: FirAnnotationCall, data: ResolutionMode): CompositeTransformResult { if (annotationCall.resolved) return annotationCall.compose() dataFlowAnalyzer.enterAnnotationCall(annotationCall) - return (annotationCall.transformChildren(transformer, data) as FirAnnotationCall).also { - // TODO: it's temporary incorrect solution until we design resolve and completion for annotation calls - it.argumentList.transformArguments(integerLiteralTypeApproximator, null) - it.replaceResolved(true) - dataFlowAnalyzer.exitAnnotationCall(it) - }.compose() + return withFirArrayOfCallTransformer { + (annotationCall.transformChildren(transformer, data) as FirAnnotationCall).also { + // TODO: it's temporary incorrect solution until we design resolve and completion for annotation calls + it.argumentList.transformArguments(integerLiteralTypeApproximator, null) + it.replaceResolved(true) + dataFlowAnalyzer.exitAnnotationCall(it) + }.compose() + } } private fun ConeTypeProjection.toFirTypeProjection(): FirTypeProjection = when (this) { diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/FirTypeUtils.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/FirTypeUtils.kt index d61f7917af5..9e19365e94c 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/FirTypeUtils.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/FirTypeUtils.kt @@ -5,7 +5,6 @@ package org.jetbrains.kotlin.fir.types -import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall import org.jetbrains.kotlin.fir.expressions.FirConstKind import org.jetbrains.kotlin.fir.symbols.StandardClassIds @@ -22,6 +21,10 @@ val FirTypeRef.isNullableNothing: Boolean get() = isBuiltinType(StandardClassIds val FirTypeRef.isUnit: Boolean get() = isBuiltinType(StandardClassIds.Unit, false) val FirTypeRef.isBoolean: Boolean get() = isBuiltinType(StandardClassIds.Boolean, false) val FirTypeRef.isEnum: Boolean get() = isBuiltinType(StandardClassIds.Enum, false) +val FirTypeRef.isArrayType: Boolean + get() = + isBuiltinType(StandardClassIds.Array, false) || + StandardClassIds.primitiveArrayTypeByElementType.values.any { isBuiltinType(it, false) } private fun FirTypeRef.isBuiltinType(classId: ClassId, isNullable: Boolean): Boolean { val type = when (this) { diff --git a/compiler/testData/codegen/box/annotations/kt10136.kt b/compiler/testData/codegen/box/annotations/kt10136.kt index 33a2f4fdd96..45c882ac31c 100644 --- a/compiler/testData/codegen/box/annotations/kt10136.kt +++ b/compiler/testData/codegen/box/annotations/kt10136.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR // TARGET_BACKEND: JVM // WITH_RUNTIME diff --git a/compiler/testData/codegen/box/reflection/createAnnotation/arrayOfKClasses.kt b/compiler/testData/codegen/box/reflection/createAnnotation/arrayOfKClasses.kt index 4910b76021e..0e1230c83b3 100644 --- a/compiler/testData/codegen/box/reflection/createAnnotation/arrayOfKClasses.kt +++ b/compiler/testData/codegen/box/reflection/createAnnotation/arrayOfKClasses.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR // IGNORE_BACKEND: JS_IR // IGNORE_BACKEND: JS_IR_ES6 // TODO: muted automatically, investigate should it be ran for JS or not diff --git a/compiler/testData/codegen/box/reflection/createAnnotation/enumKClassAnnotation.kt b/compiler/testData/codegen/box/reflection/createAnnotation/enumKClassAnnotation.kt index 7bcbb505bde..02a1c364a08 100644 --- a/compiler/testData/codegen/box/reflection/createAnnotation/enumKClassAnnotation.kt +++ b/compiler/testData/codegen/box/reflection/createAnnotation/enumKClassAnnotation.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR // IGNORE_BACKEND: JS_IR // IGNORE_BACKEND: JS_IR_ES6 // TODO: muted automatically, investigate should it be ran for JS or not diff --git a/compiler/testData/codegen/box/reflection/kClassInAnnotation/array.kt b/compiler/testData/codegen/box/reflection/kClassInAnnotation/array.kt index d636fa17354..eb5fa7c620a 100644 --- a/compiler/testData/codegen/box/reflection/kClassInAnnotation/array.kt +++ b/compiler/testData/codegen/box/reflection/kClassInAnnotation/array.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR // TARGET_BACKEND: JVM // WITH_REFLECT diff --git a/compiler/testData/ir/irText/declarations/annotations/arrayInAnnotationArguments.fir.txt b/compiler/testData/ir/irText/declarations/annotations/arrayInAnnotationArguments.fir.txt index ddf5ef01dc2..573f4a32674 100644 --- a/compiler/testData/ir/irText/declarations/annotations/arrayInAnnotationArguments.fir.txt +++ b/compiler/testData/ir/irText/declarations/annotations/arrayInAnnotationArguments.fir.txt @@ -58,7 +58,7 @@ FILE fqName: fileName:/arrayInAnnotationArguments.kt FUN name:test1 visibility:public modality:FINAL <> () returnType:kotlin.Unit annotations: TestAnnWithIntArray(x = CALL 'public final fun intArrayOf (vararg elements: kotlin.Int): kotlin.IntArray declared in kotlin' type=kotlin.IntArray origin=null) - TestAnnWithStringArray(x = CALL 'public final fun arrayOf (vararg elements: T of kotlin.arrayOf): kotlin.Array [inline] declared in kotlin' type=kotlin.Array origin=null) + TestAnnWithStringArray(x = ['a', 'b', 'c']) BLOCK_BODY FUN name:test2 visibility:public modality:FINAL <> () returnType:kotlin.Unit annotations: