diff --git a/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeBuiltinTypeUtils.kt b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeBuiltinTypeUtils.kt index aaf08c38338..5f9a12c620e 100644 --- a/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeBuiltinTypeUtils.kt +++ b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeBuiltinTypeUtils.kt @@ -56,8 +56,11 @@ val ConeKotlinType.isNonPrimitiveArray: Boolean val ConeKotlinType.isPrimitiveArray: Boolean get() = this is ConeClassLikeType && lookupTag.classId in StandardClassIds.primitiveArrayTypeByElementType.values +val ConeKotlinType.isUnsignedArray: Boolean + get() = this is ConeClassLikeType && lookupTag.classId in StandardClassIds.unsignedArrayTypeByElementType.values + val ConeKotlinType.isPrimitiveOrUnsignedArray: Boolean - get() = this is ConeClassLikeType && (lookupTag.classId in StandardClassIds.primitiveArrayTypeByElementType.values || lookupTag.classId in StandardClassIds.unsignedArrayTypeByElementType.values) + get() = isPrimitiveArray || isUnsignedArray val ConeKotlinType.isUnsignedTypeOrNullableUnsignedType: Boolean get() = isAnyOfBuiltinType(StandardClassIds.unsignedTypes) val ConeKotlinType.isUnsignedType: Boolean get() = isUnsignedTypeOrNullableUnsignedType && nullability == ConeNullability.NOT_NULL 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 f293a0f50b5..ba6f8e664f5 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt @@ -530,24 +530,34 @@ class FirCallResolver( 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. + // We want to "desugar" array literal arguments to arrayOf, intArrayOf, floatArrayOf and other *arrayOf* calls + // 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. + // We don't want to force full completion before the whole call is completed so that type variables are preserved. + // But we need to pass expectType to figure out the correct *arrayOf* function (because Array and primitive arrays can't be matched). 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) + annotation.arguments.mapTo(arguments) { arg -> + val resolutionMode = if (arg.unwrapArgument() is FirArrayOfCall) { + (argumentsToParameters[arg]?.returnTypeRef as? FirResolvedTypeRef)?.let { + // Enabling expectedTypeMismatchIsReportedInChecker clarifies error messages: + // It will be reported single ARGUMENT_TYPE_MISMATCH on the array literal in checkApplicabilityForArgumentType + // instead of several TYPE_MISMATCH for every mismatched argument. + ResolutionMode.WithExpectedType( + it, + forceFullCompletion = false, + expectedTypeMismatchIsReportedInChecker = true + ) + } ?: ResolutionMode.ContextDependent.Default + } else { + ResolutionMode.ContextDependent + } + + arg.transformSingle(transformer, resolutionMode) } }) } else { 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 7d1d7cd7edf..ecdb7c11f80 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,11 +18,6 @@ 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/FirSyntheticCallGenerator.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSyntheticCallGenerator.kt index 691e93b5619..727d47045df 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSyntheticCallGenerator.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSyntheticCallGenerator.kt @@ -6,11 +6,16 @@ package org.jetbrains.kotlin.fir.resolve.transformers import org.jetbrains.kotlin.KtFakeSourceElementKind +import org.jetbrains.kotlin.builtins.PrimitiveType import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.fakeElement import org.jetbrains.kotlin.fir.FirElement +import org.jetbrains.kotlin.fir.caches.FirCache +import org.jetbrains.kotlin.fir.caches.createCache +import org.jetbrains.kotlin.fir.caches.firCachesFactory +import org.jetbrains.kotlin.fir.caches.getValue import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.builder.FirSimpleFunctionBuilder import org.jetbrains.kotlin.fir.declarations.builder.buildTypeParameter @@ -23,7 +28,6 @@ import org.jetbrains.kotlin.fir.expressions.builder.buildFunctionCall import org.jetbrains.kotlin.fir.moduleData import org.jetbrains.kotlin.fir.references.FirReference import org.jetbrains.kotlin.fir.references.FirResolvedCallableReference -import org.jetbrains.kotlin.fir.references.builder.buildErrorNamedReference import org.jetbrains.kotlin.fir.references.builder.buildResolvedErrorReference import org.jetbrains.kotlin.fir.references.impl.FirStubReference import org.jetbrains.kotlin.fir.references.isError @@ -32,7 +36,6 @@ import org.jetbrains.kotlin.fir.resolve.ResolutionMode import org.jetbrains.kotlin.fir.resolve.calls.* import org.jetbrains.kotlin.fir.resolve.createErrorReferenceWithExistingCandidate import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeInapplicableCandidateError -import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedNameError import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider import org.jetbrains.kotlin.fir.resolve.toErrorReference import org.jetbrains.kotlin.fir.resolvedTypeFromPrototype @@ -63,12 +66,7 @@ class FirSyntheticCallGenerator( private val idFunction: FirSimpleFunction = generateSyntheticSelectFunction(SyntheticCallableId.ID) private val checkNotNullFunction: FirSimpleFunction = generateSyntheticCheckNotNullFunction() private val elvisFunction: FirSimpleFunction = generateSyntheticElvisFunction() - - private val arrayOfSymbol by lazy(LazyThreadSafetyMode.NONE) { - session.symbolProvider - .getTopLevelFunctionSymbols(StandardNames.BUILT_INS_PACKAGE_FQ_NAME, ArrayFqNames.ARRAY_OF_FUNCTION) - .firstOrNull() - } + private val arrayOfSymbolCache: FirCache = session.firCachesFactory.createCache(::getArrayOfSymbol) private fun assertSyntheticResolvableReferenceIsNotResolved(resolvable: FirResolvable) { // All synthetic calls (FirWhenExpression, FirTryExpression, FirElvisExpression, FirCheckNotNullCall) @@ -166,26 +164,51 @@ class FirSyntheticCallGenerator( } } - fun generateSyntheticArrayOfCall(arrayOfCall: FirArrayOfCall, context: ResolutionContext): FirFunctionCall { + fun generateSyntheticArrayOfCall( + arrayOfCall: FirArrayOfCall, + expectedTypeRef: FirTypeRef, + context: ResolutionContext + ): FirFunctionCall { val argumentList = arrayOfCall.argumentList return buildFunctionCall { this.argumentList = argumentList - calleeReference = arrayOfSymbol?.let { - generateCalleeReferenceWithCandidate( - arrayOfCall, - it.fir, - argumentList, - ArrayFqNames.ARRAY_OF_FUNCTION, - callKind = CallKind.Function, - context = context, - ) - } ?: buildErrorNamedReference { - diagnostic = ConeUnresolvedNameError(ArrayFqNames.ARRAY_OF_FUNCTION) - } + calleeReference = generateCalleeReferenceWithCandidate( + arrayOfCall, + calculateArrayOfSymbol(expectedTypeRef).fir, + argumentList, + ArrayFqNames.ARRAY_OF_FUNCTION, + callKind = CallKind.Function, + context = context, + ) source = arrayOfCall.source } } + private fun calculateArrayOfSymbol(expectedTypeRef: FirTypeRef): FirNamedFunctionSymbol { + val coneType = expectedTypeRef.coneType + val arrayCallName = when { + coneType.isPrimitiveArray -> { + val arrayElementClassId = coneType.arrayElementType()!!.classId + val primitiveType = PrimitiveType.getByShortName(arrayElementClassId!!.shortClassName.asString()) + ArrayFqNames.PRIMITIVE_TYPE_TO_ARRAY[primitiveType]!! + } + coneType.isUnsignedArray -> { + val arrayElementClassId = coneType.arrayElementType()!!.classId + ArrayFqNames.UNSIGNED_TYPE_TO_ARRAY[arrayElementClassId!!.asSingleFqName()]!! + } + else -> { + ArrayFqNames.ARRAY_OF_FUNCTION + } + } + return arrayOfSymbolCache.getValue(arrayCallName) + } + + private fun getArrayOfSymbol(arrayOfName: Name): FirNamedFunctionSymbol { + return session.symbolProvider + .getTopLevelFunctionSymbols(StandardNames.BUILT_INS_PACKAGE_FQ_NAME, arrayOfName) + .single() + } + fun resolveCallableReferenceWithSyntheticOuterCall( callableReferenceAccess: FirCallableReferenceAccess, expectedTypeRef: FirTypeRef?, 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 950c5ac6a6b..1a9b0a55050 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 @@ -7,7 +7,6 @@ package org.jetbrains.kotlin.fir.resolve.transformers.body.resolve import org.jetbrains.kotlin.KtFakeSourceElementKind import org.jetbrains.kotlin.KtSourceElement -import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.fakeElement import org.jetbrains.kotlin.fir.* @@ -31,7 +30,6 @@ import org.jetbrains.kotlin.fir.resolve.* import org.jetbrains.kotlin.fir.resolve.calls.* import org.jetbrains.kotlin.fir.resolve.diagnostics.* import org.jetbrains.kotlin.fir.resolve.inference.FirStubInferenceSession -import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.resolve.transformers.replaceLambdaArgumentInvocationKinds import org.jetbrains.kotlin.fir.scopes.impl.isWrappedIntegerOperator @@ -47,7 +45,6 @@ import org.jetbrains.kotlin.fir.visitors.transformSingle import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.SpecialNames import org.jetbrains.kotlin.name.StandardClassIds -import org.jetbrains.kotlin.resolve.ArrayFqNames import org.jetbrains.kotlin.resolve.calls.inference.buildAbstractResultingSubstitutor import org.jetbrains.kotlin.types.AbstractTypeChecker import org.jetbrains.kotlin.types.ConstantValueKind @@ -1634,27 +1631,29 @@ open class FirExpressionsResolveTransformer(transformer: FirAbstractBodyResolveT ) } - override fun transformArrayOfCall(arrayOfCall: FirArrayOfCall, data: ResolutionMode): FirStatement = + override fun transformArrayLiteral(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 || - 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) - arrayOfCall + when (data) { + is ResolutionMode.ContextDependent.Default -> { + // Argument in non-annotation call (unsupported) or if type of array parameter is unresolved. + arrayOfCall.transformChildren(transformer, data) + arrayOfCall + } + is ResolutionMode.WithExpectedType -> { + // Default value of array parameter (Array or primitive array such as IntArray, FloatArray, ...) + // or argument for array parameter in annotation call. + arrayOfCall.transformChildren(transformer, ResolutionMode.ContextDependent) + val call = components.syntheticCallGenerator.generateSyntheticArrayOfCall(arrayOfCall, data.expectedTypeRef, resolutionContext) + callCompleter.completeCall(call, data) + arrayOfCallTransformer.transformFunctionCall(call, session) + } + else -> { + // Other unsupported usage. + val syntheticIdCall = components.syntheticCallGenerator.generateSyntheticIdCall(arrayOfCall, resolutionContext) + arrayOfCall.transformChildren(transformer, ResolutionMode.ContextDependent) + callCompleter.completeCall(syntheticIdCall, data) + arrayOfCall + } } } diff --git a/compiler/testData/diagnostics/tests/collectionLiterals/argumentsOfAnnotation.fir.kt b/compiler/testData/diagnostics/tests/collectionLiterals/argumentsOfAnnotation.fir.kt index 64fc9dcfd51..2df3a47ec0d 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]) diff --git a/compiler/testData/diagnostics/tests/collectionLiterals/collectionLiteralsAsPrimitiveArrays.fir.kt b/compiler/testData/diagnostics/tests/collectionLiterals/collectionLiteralsAsPrimitiveArrays.fir.kt index 94345de24f1..1b40265fae9 100644 --- a/compiler/testData/diagnostics/tests/collectionLiterals/collectionLiteralsAsPrimitiveArrays.fir.kt +++ b/compiler/testData/diagnostics/tests/collectionLiterals/collectionLiteralsAsPrimitiveArrays.fir.kt @@ -12,7 +12,7 @@ fun basicTypes() { } fun basicTypesWithErrors() { - val a: IntArray = [1.0] - val b: ShortArray = [1.0] - val c: CharArray = ["a"] + val a: IntArray = [1.0] + val b: ShortArray = [1.0] + val c: CharArray = ["a"] } diff --git a/compiler/testData/diagnostics/tests/collectionLiterals/collectionLiteralsWithVarargs.fir.kt b/compiler/testData/diagnostics/tests/collectionLiterals/collectionLiteralsWithVarargs.fir.kt index 8624cf006c7..ec820b9e40b 100644 --- a/compiler/testData/diagnostics/tests/collectionLiterals/collectionLiteralsWithVarargs.fir.kt +++ b/compiler/testData/diagnostics/tests/collectionLiterals/collectionLiteralsWithVarargs.fir.kt @@ -8,7 +8,7 @@ annotation class Ann4(vararg val a: String = ["/"]) annotation class Ann5(vararg val a: Ann4 = []) annotation class Ann6(vararg val a: Ann4 = [Ann4(*["a", "b"])]) -annotation class Ann7(vararg val a: Long = [1L, null, ""]) +annotation class Ann7(vararg val a: Long = [1L, null, ""]) @Ann1(*[]) fun test1_0() {} @@ -31,6 +31,9 @@ fun test5() {} @Ann6(*[]) fun test6() {} +@Ann7(1, 2) +fun test7() {} + annotation class AnnArray(val a: Array) @AnnArray(*["/"]) diff --git a/compiler/testData/diagnostics/tests/collectionLiterals/collectionLiteralsWithVarargs.kt b/compiler/testData/diagnostics/tests/collectionLiterals/collectionLiteralsWithVarargs.kt index f86bfd264cd..35e2f225567 100644 --- a/compiler/testData/diagnostics/tests/collectionLiterals/collectionLiteralsWithVarargs.kt +++ b/compiler/testData/diagnostics/tests/collectionLiterals/collectionLiteralsWithVarargs.kt @@ -31,6 +31,9 @@ fun test5() {} @Ann6(*[]) fun test6() {} +@Ann7(1, 2) +fun test7() {} + annotation class AnnArray(val a: Array) @AnnArray(*["/"]) diff --git a/compiler/testData/diagnostics/tests/collectionLiterals/collectionLiteralsWithVarargs.txt b/compiler/testData/diagnostics/tests/collectionLiterals/collectionLiteralsWithVarargs.txt index 181267ed42e..b9f5fea799b 100644 --- a/compiler/testData/diagnostics/tests/collectionLiterals/collectionLiteralsWithVarargs.txt +++ b/compiler/testData/diagnostics/tests/collectionLiterals/collectionLiteralsWithVarargs.txt @@ -7,6 +7,7 @@ package @Ann3(a = {0.0.toFloat(), Infinity.toFloat()}) public fun test3(): kotlin.Unit @Ann5(a = {Ann4(a = {"/"})}) public fun test5(): kotlin.Unit @Ann6(a = {}) public fun test6(): kotlin.Unit +@Ann7(a = {1.toLong(), 2.toLong()}) public fun test7(): kotlin.Unit @AnnArray(a = {"/"}) public fun testArray(): kotlin.Unit @Ann1(a = {{""}}) public fun testVararg(): kotlin.Unit diff --git a/compiler/testData/diagnostics/tests/collectionLiterals/defaultValuesInAnnotation.fir.kt b/compiler/testData/diagnostics/tests/collectionLiterals/defaultValuesInAnnotation.fir.kt index 3225c1b23f7..4aab0cbabeb 100644 --- a/compiler/testData/diagnostics/tests/collectionLiterals/defaultValuesInAnnotation.fir.kt +++ b/compiler/testData/diagnostics/tests/collectionLiterals/defaultValuesInAnnotation.fir.kt @@ -21,6 +21,6 @@ annotation class Base( ) annotation class Err( - val a: IntArray = [1L], + val a: IntArray = [1L], val b: Array = [1] ) diff --git a/compiler/testData/diagnostics/tests/collectionLiterals/defaultValuesWithConstantsInAnnotation.fir.kt b/compiler/testData/diagnostics/tests/collectionLiterals/defaultValuesWithConstantsInAnnotation.fir.kt index 06164f377f7..927ccba16ae 100644 --- a/compiler/testData/diagnostics/tests/collectionLiterals/defaultValuesWithConstantsInAnnotation.fir.kt +++ b/compiler/testData/diagnostics/tests/collectionLiterals/defaultValuesWithConstantsInAnnotation.fir.kt @@ -17,7 +17,7 @@ annotation class Bar( ) annotation class Baz( - val a: IntArray = [null], - val b: IntArray = [1, null, 2], - val c: IntArray = [this] + val a: IntArray = [null], + val b: IntArray = [1, null, 2], + val c: IntArray = [this] )