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 a0de51c95c5a0..ead07c4df5193 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 @@ -51,6 +51,30 @@ val ConeKotlinType.isArrayTypeOrNullableArrayType: Boolean get() = isArrayType(i val ConeKotlinType.isNonPrimitiveArray: Boolean get() = this is ConeClassLikeType && lookupTag.classId == StandardClassIds.Array +val ConeKotlinType.isIntArray: Boolean + get() = this is ConeClassLikeType && lookupTag.classId == StandardClassIds.primitiveArrayTypeByElementType[StandardClassIds.Int] + +val ConeKotlinType.isLongArray: Boolean + get() = this is ConeClassLikeType && lookupTag.classId == StandardClassIds.primitiveArrayTypeByElementType[StandardClassIds.Long] + +val ConeKotlinType.isFloatArray: Boolean + get() = this is ConeClassLikeType && lookupTag.classId == StandardClassIds.primitiveArrayTypeByElementType[StandardClassIds.Float] + +val ConeKotlinType.isDoubleArray: Boolean + get() = this is ConeClassLikeType && lookupTag.classId == StandardClassIds.primitiveArrayTypeByElementType[StandardClassIds.Double] + +val ConeKotlinType.isCharArray: Boolean + get() = this is ConeClassLikeType && lookupTag.classId == StandardClassIds.primitiveArrayTypeByElementType[StandardClassIds.Char] + +val ConeKotlinType.isByteArray: Boolean + get() = this is ConeClassLikeType && lookupTag.classId == StandardClassIds.primitiveArrayTypeByElementType[StandardClassIds.Byte] + +val ConeKotlinType.isBooleanArray: Boolean + get() = this is ConeClassLikeType && lookupTag.classId == StandardClassIds.primitiveArrayTypeByElementType[StandardClassIds.Boolean] + +val ConeKotlinType.isShortArray: Boolean + get() = this is ConeClassLikeType && lookupTag.classId == StandardClassIds.primitiveArrayTypeByElementType[StandardClassIds.Short] + val ConeKotlinType.isPrimitiveArray: Boolean get() = this is ConeClassLikeType && lookupTag.classId in StandardClassIds.primitiveArrayTypeByElementType.values diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/ArrayUtils.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/ArrayUtils.kt index 78e4e09ee77ea..97cd5d7418555 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/ArrayUtils.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/ArrayUtils.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.fir.types import org.jetbrains.kotlin.name.StandardClassIds +import org.jetbrains.kotlin.name.canBeSpreaded import org.jetbrains.kotlin.utils.addToStdlib.runIf val ConeKotlinType.isArrayOrPrimitiveArray: Boolean @@ -42,6 +43,23 @@ fun ConeKotlinType.arrayElementType(checkUnsignedArrays: Boolean = true): ConeKo } } +fun ConeKotlinType.spreadableCollectionElementType(checkUnsignedArrays: Boolean = true): ConeKotlinType? { + return when (val argument = spreadableCollectionElementTypeArgument(checkUnsignedArrays)) { + is ConeKotlinTypeProjection -> argument.type + else -> null + } +} + +private fun ConeKotlinType.spreadableCollectionElementTypeArgument(checkUnsignedArrays: Boolean = true): ConeTypeProjection? { + val type = this.lowerBoundIfFlexible() + if (type !is ConeClassLikeType) return null + val classId = type.lookupTag.classId + if (classId.canBeSpreaded()) { + return type.typeArguments.first() + } + return arrayElementType(checkUnsignedArrays) +} + private fun ConeKotlinType.arrayElementTypeArgument(checkUnsignedArrays: Boolean = true): ConeTypeProjection? { val type = this.lowerBoundIfFlexible() if (type !is ConeClassLikeType) return null @@ -55,7 +73,6 @@ private fun ConeKotlinType.arrayElementTypeArgument(checkUnsignedArrays: Boolean if (elementType != null) { return elementType.constructClassLikeType(emptyArray(), isNullable = false) } - return null } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt index ad717bcfddf9a..4c3d04837d614 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt @@ -46,7 +46,8 @@ fun Candidate.resolveArgumentExpression( sink: CheckerSink, context: ResolutionContext, isReceiver: Boolean, - isDispatch: Boolean + isDispatch: Boolean, + isSpread: Boolean = false, ) { when (argument) { is FirFunctionCall, is FirWhenExpression, is FirTryExpression, is FirCheckNotNullCall, is FirElvisExpression -> resolveSubCallArgument( @@ -56,7 +57,8 @@ fun Candidate.resolveArgumentExpression( sink, context, isReceiver, - isDispatch + isDispatch, + isSpread = isSpread ) // x?.bar() is desugared to `x SAFE-CALL-OPERATOR { $not-null-receiver$.bar() }` // @@ -75,7 +77,8 @@ fun Candidate.resolveArgumentExpression( context, isReceiver, isDispatch, - useNullableArgumentType = true + useNullableArgumentType = true, + isSpread = isSpread ) } else { // Assignment @@ -88,7 +91,8 @@ fun Candidate.resolveArgumentExpression( isReceiver = false, isDispatch = false, sink = sink, - context = context + context = context, + isSpread = isSpread ) } } @@ -101,7 +105,8 @@ fun Candidate.resolveArgumentExpression( sink, context, isReceiver, - isDispatch + isDispatch, + isSpread = isSpread ) else preprocessCallableReference(argument, expectedType, context) @@ -113,7 +118,8 @@ fun Candidate.resolveArgumentExpression( sink, context, isReceiver, - isDispatch + isDispatch, + isSpread = isSpread ) is FirBlock -> resolveBlockArgument( csBuilder, @@ -122,9 +128,10 @@ fun Candidate.resolveArgumentExpression( sink, context, isReceiver, - isDispatch + isDispatch, + isSpread =isSpread ) - else -> resolvePlainExpressionArgument(csBuilder, argument, expectedType, sink, context, isReceiver, isDispatch) + else -> resolvePlainExpressionArgument(csBuilder, argument, expectedType, sink, context, isReceiver, isDispatch, isSpread = isSpread) } } @@ -135,7 +142,8 @@ private fun Candidate.resolveBlockArgument( sink: CheckerSink, context: ResolutionContext, isReceiver: Boolean, - isDispatch: Boolean + isDispatch: Boolean, + isSpread: Boolean = false ) { val returnArguments = block.returnExpressions() if (returnArguments.isEmpty()) { @@ -148,7 +156,8 @@ private fun Candidate.resolveBlockArgument( isReceiver = false, isDispatch = false, sink = sink, - context = context + context = context, + isSpread = isSpread ) return } @@ -160,7 +169,8 @@ private fun Candidate.resolveBlockArgument( sink, context, isReceiver, - isDispatch + isDispatch, + isSpread = isSpread ) } } @@ -173,7 +183,8 @@ fun Candidate.resolveSubCallArgument( context: ResolutionContext, isReceiver: Boolean, isDispatch: Boolean, - useNullableArgumentType: Boolean = false + useNullableArgumentType: Boolean = false, + isSpread: Boolean = false ) { require(argument is FirExpression) val candidate = argument.candidate() ?: return resolvePlainExpressionArgument( @@ -184,7 +195,8 @@ fun Candidate.resolveSubCallArgument( context, isReceiver, isDispatch, - useNullableArgumentType + useNullableArgumentType, + isSpread = isSpread ) /* * It's important to extract type from argument neither from symbol, because of symbol contains @@ -201,7 +213,8 @@ fun Candidate.resolveSubCallArgument( context, isReceiver, isDispatch, - useNullableArgumentType + useNullableArgumentType, + isSpread = isSpread ) } @@ -233,7 +246,8 @@ fun Candidate.resolvePlainExpressionArgument( context: ResolutionContext, isReceiver: Boolean, isDispatch: Boolean, - useNullableArgumentType: Boolean = false + useNullableArgumentType: Boolean = false, + isSpread: Boolean = false ) { if (expectedType == null) return @@ -251,7 +265,8 @@ fun Candidate.resolvePlainExpressionArgument( context, isReceiver, isDispatch, - useNullableArgumentType + useNullableArgumentType, + isSpread = isSpread ) } @@ -264,7 +279,8 @@ fun Candidate.resolvePlainArgumentType( context: ResolutionContext, isReceiver: Boolean, isDispatch: Boolean, - useNullableArgumentType: Boolean = false + useNullableArgumentType: Boolean = false, + isSpread: Boolean = false ) { val position = if (isReceiver) ConeReceiverConstraintPosition(argument) else ConeArgumentConstraintPosition(argument) @@ -289,7 +305,7 @@ fun Candidate.resolvePlainArgumentType( } checkApplicabilityForArgumentType( - csBuilder, argument, argumentTypeForApplicabilityCheck, expectedType, position, isReceiver, isDispatch, sink, context + csBuilder, argument, argumentTypeForApplicabilityCheck, expectedType, position, isReceiver, isDispatch, sink, context, isSpread = isSpread ) } @@ -332,16 +348,28 @@ private fun checkApplicabilityForArgumentType( csBuilder: ConstraintSystemBuilder, argument: FirExpression, argumentTypeBeforeCapturing: ConeKotlinType, - expectedType: ConeKotlinType?, + initialExpectedType: ConeKotlinType?, position: ConstraintPosition, isReceiver: Boolean, isDispatch: Boolean, sink: CheckerSink, - context: ResolutionContext + context: ResolutionContext, + isSpread: Boolean = false ) { - if (expectedType == null) return + var expectedType = initialExpectedType ?: return + var argumentType = captureFromTypeParameterUpperBoundIfNeeded(argumentTypeBeforeCapturing, expectedType, context.session) + + if (isSpread && !argumentType.isNullable) { + argumentType = argumentType.spreadableCollectionElementType()?.also { + expectedType = + expectedType.arrayElementType() + ?: error( + "Could not retrieve expected element type for vararg parameter." + + " Parameter type is ${expectedType.renderReadable()}" + ) + } ?: argumentType + } - val argumentType = captureFromTypeParameterUpperBoundIfNeeded(argumentTypeBeforeCapturing, expectedType, context.session) fun subtypeError(actualExpectedType: ConeKotlinType): ResolutionDiagnostic { if (argument.isNullLiteral && actualExpectedType.nullability == ConeNullability.NOT_NULL) { @@ -413,6 +441,7 @@ private fun checkApplicabilityForArgumentType( } } + if (!isReceiver) { sink.reportDiagnostic(subtypeError(expectedType)) return @@ -427,6 +456,7 @@ private fun checkApplicabilityForArgumentType( sink.reportDiagnostic(InapplicableWrongReceiver(expectedType, argumentType)) } } + } internal fun Candidate.resolveArgument( @@ -449,7 +479,8 @@ internal fun Candidate.resolveArgument( sink, context, isReceiver, - false + false, + isSpread = argument is FirSpreadArgumentExpression && parameter?.isVararg == 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 c6057a94df8b4..ceb0b0f17bb86 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 @@ -32,7 +32,7 @@ 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.substitution.ConeSubstitutor -import org.jetbrains.kotlin.fir.resolve.transformers.replaceLambdaArgumentInvocationKinds +import org.jetbrains.kotlin.fir.resolve.transformers.* import org.jetbrains.kotlin.fir.scopes.impl.isWrappedIntegerOperator import org.jetbrains.kotlin.fir.scopes.impl.isWrappedIntegerOperatorForUnsignedType import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol @@ -52,6 +52,100 @@ import org.jetbrains.kotlin.types.TypeApproximatorConfiguration import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.util.PrivateForInline + +enum class ToArrayCast { + NO_CAST, + TYPE_ARRAY_CAST, + INT_ARRAY_CAST, + LONG_ARRAY_CAST, + FLOAT_ARRAY_CAST, + DOUBLE_ARRAY_CAST, + BOOLEAN_ARRAY_CAST, + BYTE_ARRAY_CAST, + CHAR_ARRAY_CAST, + SHORT_ARRAY_CAST +} + +fun ToArrayCast.getFunctionName(): String { + return when(this) { + ToArrayCast.TYPE_ARRAY_CAST -> "toTypedArray" + ToArrayCast.INT_ARRAY_CAST -> "toIntArray" + ToArrayCast.LONG_ARRAY_CAST -> "toLongArray" + ToArrayCast.FLOAT_ARRAY_CAST -> "toFloatArray" + ToArrayCast.DOUBLE_ARRAY_CAST -> "toDoubleArray" + ToArrayCast.BOOLEAN_ARRAY_CAST -> "toBooleanArray" + ToArrayCast.BYTE_ARRAY_CAST -> "toByteArray" + ToArrayCast.CHAR_ARRAY_CAST -> "toCharArray" + ToArrayCast.SHORT_ARRAY_CAST -> "toShortArray" + else -> throw IllegalArgumentException("No cast for $this") + } +} +class SpreadArgumentsCastTransformer(override val session: FirSession, private val transformer: FirAbstractBodyResolveTransformerDispatcher) : + FirAbstractPhaseTransformer(FirResolvePhase.BODY_RESOLVE) { + + override fun transformSpreadArgumentExpression( + spreadArgumentExpression: FirSpreadArgumentExpression, + data: ToArrayCast?, + ): FirStatement { + if (data == null || data == ToArrayCast.NO_CAST) return spreadArgumentExpression + + val function = buildFunctionCall { + this.explicitReceiver = spreadArgumentExpression.expression + this.extensionReceiver = spreadArgumentExpression.expression + this.calleeReference = buildSimpleNamedReference { + this.name = Name.identifier(data.getFunctionName()) + } + this.origin = FirFunctionCallOrigin.Regular + }.transformSingle(transformer, ResolutionMode.ContextIndependent) + + + return buildSpreadArgumentExpression { + this.source = spreadArgumentExpression.source + this.annotations.addAll(spreadArgumentExpression.annotations) + this.expression = function + } + } + + override fun transformVarargArgumentsExpression( + varargArgumentsExpression: FirVarargArgumentsExpression, + data: ToArrayCast?, + ): FirStatement { + return buildVarargArgumentsExpression { + source = varargArgumentsExpression.source + coneTypeOrNull = varargArgumentsExpression.resolvedType + annotations.addAll(varargArgumentsExpression.annotations) + coneElementTypeOrNull = varargArgumentsExpression.coneElementTypeOrNull + arguments.addAll(varargArgumentsExpression.arguments.map { firExpression -> + if (firExpression is FirSpreadArgumentExpression && !firExpression.expression.resolvedType.hasError()) { + val expectedType = varargArgumentsExpression.resolvedType + + val neededCast = when { + firExpression.resolvedType.isSubtypeOf(expectedType, session) -> ToArrayCast.NO_CAST + expectedType.isNonPrimitiveArray -> ToArrayCast.TYPE_ARRAY_CAST + expectedType.isIntArray -> ToArrayCast.INT_ARRAY_CAST + expectedType.isLongArray -> ToArrayCast.LONG_ARRAY_CAST + expectedType.isFloatArray -> ToArrayCast.FLOAT_ARRAY_CAST + expectedType.isDoubleArray -> ToArrayCast.DOUBLE_ARRAY_CAST + expectedType.isBooleanArray -> ToArrayCast.BOOLEAN_ARRAY_CAST + expectedType.isByteArray -> ToArrayCast.BYTE_ARRAY_CAST + expectedType.isCharArray -> ToArrayCast.CHAR_ARRAY_CAST + expectedType.isShortArray -> ToArrayCast.SHORT_ARRAY_CAST + else -> ToArrayCast.NO_CAST + } + firExpression.transform(this@SpreadArgumentsCastTransformer, neededCast) + } else { + firExpression + } + }) + } + } + + override fun transformElement(element: E, data: ToArrayCast?): E { + return element + } +} + + open class FirExpressionsResolveTransformer(transformer: FirAbstractBodyResolveTransformerDispatcher) : FirPartialBodyResolveTransformer(transformer) { private inline val builtinTypes: BuiltinTypes get() = session.builtinTypes @@ -445,7 +539,10 @@ open class FirExpressionsResolveTransformer(transformer: FirAbstractBodyResolveT dataFlowAnalyzer.exitFunctionCall(result, data.forceFullCompletion) } - addReceiversFromExtensions(result) + (result.argumentList as? FirResolvedArgumentList)?.transformArguments( + SpreadArgumentsCastTransformer(session, transformer), + null + ) if (enableArrayOfCallTransformation) { return arrayOfCallTransformer.transformFunctionCall(result, session) diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeUtils.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeUtils.kt index 6e7d27028bd53..67135a0601082 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeUtils.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeUtils.kt @@ -76,4 +76,4 @@ fun IrType.toArrayOrPrimitiveArrayType(irBuiltIns: IrBuiltIns): IrType = ?: throw AssertionError("$this not in primitiveArrayForType") } else { irBuiltIns.arrayClass.typeWith(this) - } + } \ No newline at end of file diff --git a/compiler/testData/resolve/varargs/SpreadOnNonArrayCollections.resolve b/compiler/testData/resolve/varargs/SpreadOnNonArrayCollections.resolve new file mode 100644 index 0000000000000..a606cefa6626f --- /dev/null +++ b/compiler/testData/resolve/varargs/SpreadOnNonArrayCollections.resolve @@ -0,0 +1,228 @@ +~boolvararg~fun booleanVararg(vararg xs: Boolean) {} +~charvararg~fun charVararg(vararg xs: Char) {} +~bytevararg~fun byteVararg(vararg xs: Byte) {} +~shortvararg~fun shortVararg(vararg xs: Short) {} +~intvararg~fun intVararg(vararg xs: Int) {} +~longvararg~fun longVararg(vararg xs: Long) {} +~floatvararg~fun floatVararg(vararg xs: Float) {} +~doublevararg~fun doubleVararg(vararg xs: Double) {} +~anyvararg~fun anyVararg(vararg xs: Any?) {} +~genericvararg~fun genericVararg(vararg xs: T) {} +~stringvararg~fun stringVararg(vararg xs: String) {} + +class A {} + + +fun bar() { + val booleanList = listOf(true) + val booleanArray = booleanArrayOf(true) + val booleanSet = setOf(true) + + `boolvararg``boolvararg`booleanVararg() + `boolvararg``boolvararg`booleanVararg(true, false) + `boolvararg``boolvararg`booleanVararg(*listOf(true)) + `boolvararg`booleanVararg(*booleanArrayOf(true)) + `boolvararg`booleanVararg(*booleanList) + `boolvararg`booleanVararg(*booleanArray) + `boolvararg`booleanVararg(*booleanSet) + `boolvararg`booleanVararg( + *listOf(true, false), + *setOf(true, false), + *mutableSetOf(true, false), + *mutableListOf(true, false), + *booleanArrayOf(true, false), + *arrayOf(true, false) + ) + + val charList = listOf('a') + val charArray = charArrayOf('a') + val charSet = setOf('a') + `charvararg`charVararg() + `charvararg`charVararg('a', 'b') + `charvararg`charVararg(*listOf('a')) + `charvararg`charVararg(*charArrayOf('a')) + `charvararg`charVararg(*charList) + `charvararg`charVararg(*charArray) + `charvararg`charVararg(*charSet) + `charvararg`charVararg( + *listOf('a', 'b'), + *setOf('a', 'b'), + *mutableSetOf('a', 'b'), + *mutableListOf('a', 'b'), + *charArrayOf('a', 'b'), + *arrayOf('a', 'b') + ) + + val byteList = listOf(1.toByte()) + val byteArray = byteArrayOf(1) + val byteSet = setOf(1.toByte()) + `bytevararg`byteVararg() + `bytevararg`byteVararg(1.toByte()) + `bytevararg`byteVararg(*listOf(1)) + `bytevararg`byteVararg(*byteArrayOf(1)) + `bytevararg`byteVararg(*byteList) + `bytevararg`byteVararg(*byteArray) + `bytevararg`byteVararg(*byteSet) + `bytevararg`byteVararg( + *listOf(1.toByte()), + *setOf(1), + *mutableSetOf(1), + *mutableListOf(1), + *byteArrayOf(1), + *arrayOf(1) + ) + + val shortList = listOf(1.toShort()) + val shortArray = shortArrayOf(1) + val shortSet = setOf(1.toShort()) + `shortvararg`shortVararg() + `shortvararg`shortVararg(1.toShort()) + `shortvararg`shortVararg(*listOf(1)) + `shortvararg`shortVararg(*shortArrayOf(1)) + `shortvararg`shortVararg(*shortList) + `shortvararg`shortVararg(*shortArray) + `shortvararg`shortVararg(*shortSet) + `shortvararg`shortVararg( + *listOf(1.toShort()), + *setOf(1), + *mutableSetOf(1), + *mutableListOf(1), + *shortArrayOf(1), + *arrayOf(1) + ) + + val intList = listOf(1) + val intArray = intArrayOf(1) + val intSet = setOf(1) + `intvararg`intVararg() + `intvararg`intVararg(1, 2) + `intvararg`intVararg(*listOf(1)) + `intvararg`intVararg(*intArrayOf(1)) + `intvararg`intVararg(*intList) + `intvararg`intVararg(*intArray) + `intvararg`intVararg(*intSet) + `intvararg`intVararg( + *listOf(1), + *setOf(1), + *mutableSetOf(1), + *mutableListOf(1), + *intArrayOf(1), + *arrayOf(1) + ) + + val longList = listOf(1L) + val longArray = longArrayOf(1L) + val longSet = setOf(1L) + `longvararg`longVararg() + `longvararg`longVararg(1L) + `longvararg`longVararg(*listOf(1L)) + `longvararg`longVararg(*longArrayOf(1L)) + `longvararg`longVararg(*longList) + `longvararg`longVararg(*longArray) + `longvararg`longVararg(*longSet) + `longvararg`longVararg( + *listOf(1L), + *setOf(1L), + *mutableSetOf(1L), + *mutableListOf(1L), + *longArrayOf(1L), + *arrayOf(1L) + ) + + val floatList = listOf(1.0f) + val floatArray = floatArrayOf(1.0f) + val floatSet = setOf(1.0f) + `floatvararg`floatVararg() + `floatvararg`floatVararg(1.0f) + `floatvararg`floatVararg(*listOf(1.0f)) + `floatvararg`floatVararg(*floatArrayOf(1.0f)) + `floatvararg`floatVararg(*floatList) + `floatvararg`floatVararg(*floatArray) + `floatvararg`floatVararg(*floatSet) + `floatvararg`floatVararg( + *listOf(1.0f), + *setOf(1.0f), + *mutableSetOf(1.0f), + *mutableListOf(1.0f), + *floatArrayOf(1.0f), + *arrayOf(1.0f) + ) + + val doubleList = listOf(1.0) + val doubleArray = doubleArrayOf(1.0) + val doubleSet = setOf(1.0) + `doublevararg`doubleVararg() + `doublevararg`doubleVararg(1.0) + `doublevararg`doubleVararg(*listOf(1.0)) + `doublevararg`doubleVararg(*doubleArrayOf(1.0)) + `doublevararg`doubleVararg(*doubleList) + `doublevararg`doubleVararg(*doubleArray) + `doublevararg`doubleVararg(*doubleSet) + `doublevararg`doubleVararg( + *listOf(1.0), + *setOf(1.0), + *mutableSetOf(1.0), + *mutableListOf(1.0), + *doubleArrayOf(1.0), + *arrayOf(1.0) + ) + + `anyvararg`anyVararg() + `anyvararg`anyVararg('a', 5) + `anyvararg`anyVararg(*listOf('a')) + `anyvararg`anyVararg(*listOf(A())) + `anyvararg`anyVararg(*intList) + `anyvararg`anyVararg(*intArray) + `anyvararg`anyVararg(*intSet, *charSet, *byteArray) + `anyvararg`anyVararg( + *listOf('a'), + *setOf('a'), + *mutableSetOf('a'), + *mutableListOf('a'), + *arrayOf('a'), + *charArrayOf('a'), + *intArray, + *byteArray + ) + + + `genericvararg`genericVararg(*listOf("a")) + `genericvararg`genericVararg(1, 'a', "a") + `genericvararg`genericVararg( + *intList + ) + `genericvararg`genericVararg( + *intList, + *intSet, + *charSet, + *byteArray + ) + `genericvararg`genericVararg( + *listOf(true), + *setOf(1L), + *mutableSetOf(1.0), + *mutableListOf("a"), + *arrayOf("a"), + *intArrayOf(1), + *arrayOf(A()), + *listOf(A()) + ) + + val stringList = listOf("a") + val stringArray = arrayOf("a") + val stringSet = setOf("a") + `stringvararg`stringVararg() + `stringvararg`stringVararg("a", "b") + `stringvararg`stringVararg(*listOf("a")) + `stringvararg`stringVararg(*stringArray) + `stringvararg`stringVararg(*stringList) + `stringvararg`stringVararg(*stringSet) + `stringvararg`stringVararg( + *listOf("a", "b"), + *setOf("a", "b"), + *mutableSetOf("a", "b"), + *mutableListOf("a", "b"), + *arrayOf("a", "b"), + *stringArray + ) +} \ No newline at end of file diff --git a/compiler/tests-gen/org/jetbrains/kotlin/resolve/ResolveTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/resolve/ResolveTestGenerated.java index e4758db3ca530..721907ba7e5f0 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/resolve/ResolveTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/resolve/ResolveTestGenerated.java @@ -461,6 +461,11 @@ public void testNilaryVsVararg() throws Exception { runTest("compiler/testData/resolve/varargs/NilaryVsVararg.resolve"); } + @TestMetadata("SpreadOnNonArrayCollections.resolve") + public void testSpreadOnNonArrayCollections() throws Exception { + runTest("compiler/testData/resolve/varargs/SpreadOnNonArrayCollections.resolve"); + } + @TestMetadata("UnaryVsVararg.resolve") public void testUnaryVsVararg() throws Exception { runTest("compiler/testData/resolve/varargs/UnaryVsVararg.resolve"); diff --git a/core/compiler.common/src/org/jetbrains/kotlin/name/StandardClassIds.kt b/core/compiler.common/src/org/jetbrains/kotlin/name/StandardClassIds.kt index eac2407f463a6..6e6327921b201 100644 --- a/core/compiler.common/src/org/jetbrains/kotlin/name/StandardClassIds.kt +++ b/core/compiler.common/src/org/jetbrains/kotlin/name/StandardClassIds.kt @@ -261,6 +261,17 @@ private fun String.coroutinesId() = ClassId(StandardClassIds.BASE_COROUTINES_PAC private fun String.enumsId() = ClassId(StandardClassIds.BASE_ENUMS_PACKAGE, Name.identifier(this)) private fun String.concurrentId() = ClassId(StandardClassIds.BASE_CONCURRENT_PACKAGE, Name.identifier(this)) +fun ClassId.canBeSpreaded() = listOf( + StandardClassIds.Array, + StandardClassIds.Collection, + StandardClassIds.MutableCollection, + StandardClassIds.List, + StandardClassIds.MutableList, + StandardClassIds.Set, + StandardClassIds.MutableSet, +).contains(this) + + private fun String.testId() = ClassId(StandardClassIds.BASE_TEST_PACKAGE, Name.identifier(this)) private fun String.callableId(packageName: FqName) = CallableId(packageName, Name.identifier(this))