From a782116573f67c446a63f9fe57550951577d4364 Mon Sep 17 00:00:00 2001 From: BlaBlaHuman Date: Sun, 7 Apr 2024 23:08:57 +0200 Subject: [PATCH 01/16] Add isVararg to candidate resolve --- .../kotlin/fir/resolve/calls/Arguments.kt | 62 ++++++++++++------- 1 file changed, 40 insertions(+), 22 deletions(-) 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..c30599b1dd1cf 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, + isVararg: 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, + isVararg = isVararg ) // 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, + isVararg = isVararg ) } else { // Assignment @@ -88,7 +91,8 @@ fun Candidate.resolveArgumentExpression( isReceiver = false, isDispatch = false, sink = sink, - context = context + context = context, + isVararg = isVararg ) } } @@ -101,11 +105,12 @@ fun Candidate.resolveArgumentExpression( sink, context, isReceiver, - isDispatch + isDispatch, + isVararg = isVararg ) else - preprocessCallableReference(argument, expectedType, context) - is FirAnonymousFunctionExpression -> preprocessLambdaArgument(csBuilder, argument, expectedType, context, sink) + preprocessCallableReference(argument, expectedType, context, isVararg = isVararg) + is FirAnonymousFunctionExpression -> preprocessLambdaArgument(csBuilder, argument, expectedType, context, sink, isVararg = isVararg) is FirWrappedArgumentExpression -> resolveArgumentExpression( csBuilder, argument.expression, @@ -113,7 +118,8 @@ fun Candidate.resolveArgumentExpression( sink, context, isReceiver, - isDispatch + isDispatch, + isVararg = isVararg ) is FirBlock -> resolveBlockArgument( csBuilder, @@ -122,9 +128,10 @@ fun Candidate.resolveArgumentExpression( sink, context, isReceiver, - isDispatch + isDispatch, + isVararg =isVararg ) - else -> resolvePlainExpressionArgument(csBuilder, argument, expectedType, sink, context, isReceiver, isDispatch) + else -> resolvePlainExpressionArgument(csBuilder, argument, expectedType, sink, context, isReceiver, isDispatch, isVararg = isVararg) } } @@ -135,7 +142,8 @@ private fun Candidate.resolveBlockArgument( sink: CheckerSink, context: ResolutionContext, isReceiver: Boolean, - isDispatch: Boolean + isDispatch: Boolean, + isVararg: 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, + isVararg = isVararg ) return } @@ -160,7 +169,8 @@ private fun Candidate.resolveBlockArgument( sink, context, isReceiver, - isDispatch + isDispatch, + isVararg = isVararg ) } } @@ -173,7 +183,8 @@ fun Candidate.resolveSubCallArgument( context: ResolutionContext, isReceiver: Boolean, isDispatch: Boolean, - useNullableArgumentType: Boolean = false + useNullableArgumentType: Boolean = false, + isVararg: Boolean = false ) { require(argument is FirExpression) val candidate = argument.candidate() ?: return resolvePlainExpressionArgument( @@ -184,7 +195,8 @@ fun Candidate.resolveSubCallArgument( context, isReceiver, isDispatch, - useNullableArgumentType + useNullableArgumentType, + isVararg = isVararg ) /* * 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, + isVararg = isVararg ) } @@ -233,7 +246,8 @@ fun Candidate.resolvePlainExpressionArgument( context: ResolutionContext, isReceiver: Boolean, isDispatch: Boolean, - useNullableArgumentType: Boolean = false + useNullableArgumentType: Boolean = false, + isVararg: Boolean = false ) { if (expectedType == null) return @@ -251,7 +265,8 @@ fun Candidate.resolvePlainExpressionArgument( context, isReceiver, isDispatch, - useNullableArgumentType + useNullableArgumentType, + isVararg = isVararg ) } @@ -264,7 +279,8 @@ fun Candidate.resolvePlainArgumentType( context: ResolutionContext, isReceiver: Boolean, isDispatch: Boolean, - useNullableArgumentType: Boolean = false + useNullableArgumentType: Boolean = false, + isVararg: 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, isVararg = isVararg ) } @@ -337,7 +353,8 @@ private fun checkApplicabilityForArgumentType( isReceiver: Boolean, isDispatch: Boolean, sink: CheckerSink, - context: ResolutionContext + context: ResolutionContext, + isVararg: Boolean = false ) { if (expectedType == null) return @@ -449,7 +466,8 @@ internal fun Candidate.resolveArgument( sink, context, isReceiver, - false + false, + isVararg = parameter?.isVararg == true ) } From fd044492520dd2570a8df647c23b6f6142976ef5 Mon Sep 17 00:00:00 2001 From: BlaBlaHuman Date: Mon, 8 Apr 2024 14:35:42 +0200 Subject: [PATCH 02/16] Update `irTypeUtils` --- .../jetbrains/kotlin/ir/types/IrTypeUtils.kt | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) 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..b27a0d953852e 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 @@ -9,7 +9,10 @@ import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.ir.IrBuiltIns import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable +import org.jetbrains.kotlin.ir.util.isPrimitiveArray +import org.jetbrains.kotlin.ir.util.render import org.jetbrains.kotlin.types.AbstractTypeChecker +import org.jetbrains.kotlin.types.checker.SimpleClassicTypeSystemContext.extractTypeParameters fun IrClassifierSymbol.superTypes(): List = when (this) { is IrClassSymbol -> owner.superTypes @@ -53,8 +56,17 @@ fun IrType.isNullable(): Boolean = val IrType.isBoxedArray: Boolean get() = classOrNull?.owner?.fqNameWhenAvailable == StandardNames.FqNames.array.toSafe() + fun IrType.getArrayElementType(irBuiltIns: IrBuiltIns): IrType = - if (isBoxedArray) { + if (isPrimitiveArray()) { + println("getArrayElementType primitive") + val classifier = this.classOrNull!! + irBuiltIns.primitiveArrayElementTypes[classifier] + ?: irBuiltIns.unsignedArraysElementTypes[classifier] + ?: throw AssertionError("Primitive array expected: $classifier") + } + else { + println("getArrayElementType boxedarray") when (val argument = (this as IrSimpleType).arguments.singleOrNull()) { is IrTypeProjection -> argument.type @@ -63,11 +75,6 @@ fun IrType.getArrayElementType(irBuiltIns: IrBuiltIns): IrType = null -> error("Unexpected array argument type: null") } - } else { - val classifier = this.classOrNull!! - irBuiltIns.primitiveArrayElementTypes[classifier] - ?: irBuiltIns.unsignedArraysElementTypes[classifier] - ?: throw AssertionError("Primitive array expected: $classifier") } fun IrType.toArrayOrPrimitiveArrayType(irBuiltIns: IrBuiltIns): IrType = From 46bcc523dd7727bd40e02c777debffdba7abbfa3 Mon Sep 17 00:00:00 2001 From: BlaBlaHuman Date: Wed, 10 Apr 2024 11:11:50 +0200 Subject: [PATCH 03/16] Cast collections to the corresponding array on the front-end --- .../kotlin/fir/types/ConeBuiltinTypeUtils.kt | 24 +++++ .../kotlin/fir/resolve/calls/Arguments.kt | 8 +- .../FirExpressionsResolveTransformer.kt | 100 +++++++++++++++++- 3 files changed, 128 insertions(+), 4 deletions(-) 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/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt index c30599b1dd1cf..daea6cb52fd5c 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 @@ -109,8 +109,8 @@ fun Candidate.resolveArgumentExpression( isVararg = isVararg ) else - preprocessCallableReference(argument, expectedType, context, isVararg = isVararg) - is FirAnonymousFunctionExpression -> preprocessLambdaArgument(csBuilder, argument, expectedType, context, sink, isVararg = isVararg) + preprocessCallableReference(argument, expectedType, context) + is FirAnonymousFunctionExpression -> preprocessLambdaArgument(csBuilder, argument, expectedType, context, sink) is FirWrappedArgumentExpression -> resolveArgumentExpression( csBuilder, argument.expression, @@ -430,6 +430,10 @@ private fun checkApplicabilityForArgumentType( } } + + if (isVararg) + return + if (!isReceiver) { sink.reportDiagnostic(subtypeError(expectedType)) return 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..66d186278c36e 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,99 @@ 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) { + 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 +538,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) From 36b3dcbd82991512bf0f129fb304c7cb0087f286 Mon Sep 17 00:00:00 2001 From: BlaBlaHuman Date: Fri, 12 Apr 2024 15:55:12 +0200 Subject: [PATCH 04/16] Fix type inference --- .../kotlin/fir/types/ConeBuiltinTypeUtils.kt | 4 ++++ .../src/org/jetbrains/kotlin/fir/types/ArrayUtils.kt | 3 ++- .../jetbrains/kotlin/fir/resolve/calls/Arguments.kt | 12 ++++++++---- .../org/jetbrains/kotlin/name/StandardClassIds.kt | 11 +++++++++++ 4 files changed, 25 insertions(+), 5 deletions(-) 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 ead07c4df5193..9fb6025b0cc68 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,10 @@ val ConeKotlinType.isArrayTypeOrNullableArrayType: Boolean get() = isArrayType(i val ConeKotlinType.isNonPrimitiveArray: Boolean get() = this is ConeClassLikeType && lookupTag.classId == StandardClassIds.Array +val ConeKotlinType.isNonPrimitiveGenericArray: Boolean + get() = this is ConeClassLikeType && lookupTag.classId == StandardClassIds.Array && typeArguments.size == 1 + + val ConeKotlinType.isIntArray: Boolean get() = this is ConeClassLikeType && lookupTag.classId == StandardClassIds.primitiveArrayTypeByElementType[StandardClassIds.Int] 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..a71cff80d4ad0 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 @@ -46,7 +47,7 @@ private fun ConeKotlinType.arrayElementTypeArgument(checkUnsignedArrays: Boolean val type = this.lowerBoundIfFlexible() if (type !is ConeClassLikeType) return null val classId = type.lookupTag.classId - if (classId == StandardClassIds.Array) { + if (classId.canBeSpreaded()) { return type.typeArguments.first() } val elementType = StandardClassIds.elementTypeByPrimitiveArrayType[classId] ?: runIf(checkUnsignedArrays) { 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 daea6cb52fd5c..b48cf5117b8a4 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 @@ -357,8 +357,14 @@ private fun checkApplicabilityForArgumentType( isVararg: Boolean = false ) { if (expectedType == null) return + var argumentType = captureFromTypeParameterUpperBoundIfNeeded(argumentTypeBeforeCapturing, expectedType, context.session) + + if (isVararg) + if (expectedType.isPrimitiveArray || !expectedType.isNonPrimitiveGenericArray) + return + argumentType = argumentType.arrayElementType()?.createOutArrayType(createPrimitiveArrayType = false) ?: argumentType + } - val argumentType = captureFromTypeParameterUpperBoundIfNeeded(argumentTypeBeforeCapturing, expectedType, context.session) fun subtypeError(actualExpectedType: ConeKotlinType): ResolutionDiagnostic { if (argument.isNullLiteral && actualExpectedType.nullability == ConeNullability.NOT_NULL) { @@ -431,8 +437,6 @@ private fun checkApplicabilityForArgumentType( } - if (isVararg) - return if (!isReceiver) { sink.reportDiagnostic(subtypeError(expectedType)) @@ -471,7 +475,7 @@ internal fun Candidate.resolveArgument( context, isReceiver, false, - isVararg = parameter?.isVararg == true + isVararg = argument is FirSpreadArgumentExpression ) } 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)) From cb870b5a5a68d9a79302754bb1737cf2b97ae8c5 Mon Sep 17 00:00:00 2001 From: BlaBlaHuman Date: Fri, 12 Apr 2024 16:09:02 +0200 Subject: [PATCH 05/16] Rename argument, fix bracket --- .../kotlin/fir/resolve/calls/Arguments.kt | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) 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 b48cf5117b8a4..0cad81c25a4b3 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 @@ -47,7 +47,7 @@ fun Candidate.resolveArgumentExpression( context: ResolutionContext, isReceiver: Boolean, isDispatch: Boolean, - isVararg: Boolean = false, + isSpread: Boolean = false, ) { when (argument) { is FirFunctionCall, is FirWhenExpression, is FirTryExpression, is FirCheckNotNullCall, is FirElvisExpression -> resolveSubCallArgument( @@ -58,7 +58,7 @@ fun Candidate.resolveArgumentExpression( context, isReceiver, isDispatch, - isVararg = isVararg + isSpread = isSpread ) // x?.bar() is desugared to `x SAFE-CALL-OPERATOR { $not-null-receiver$.bar() }` // @@ -78,7 +78,7 @@ fun Candidate.resolveArgumentExpression( isReceiver, isDispatch, useNullableArgumentType = true, - isVararg = isVararg + isSpread = isSpread ) } else { // Assignment @@ -92,7 +92,7 @@ fun Candidate.resolveArgumentExpression( isDispatch = false, sink = sink, context = context, - isVararg = isVararg + isSpread = isSpread ) } } @@ -106,7 +106,7 @@ fun Candidate.resolveArgumentExpression( context, isReceiver, isDispatch, - isVararg = isVararg + isSpread = isSpread ) else preprocessCallableReference(argument, expectedType, context) @@ -119,7 +119,7 @@ fun Candidate.resolveArgumentExpression( context, isReceiver, isDispatch, - isVararg = isVararg + isSpread = isSpread ) is FirBlock -> resolveBlockArgument( csBuilder, @@ -129,9 +129,9 @@ fun Candidate.resolveArgumentExpression( context, isReceiver, isDispatch, - isVararg =isVararg + isSpread =isSpread ) - else -> resolvePlainExpressionArgument(csBuilder, argument, expectedType, sink, context, isReceiver, isDispatch, isVararg = isVararg) + else -> resolvePlainExpressionArgument(csBuilder, argument, expectedType, sink, context, isReceiver, isDispatch, isSpread = isSpread) } } @@ -143,7 +143,7 @@ private fun Candidate.resolveBlockArgument( context: ResolutionContext, isReceiver: Boolean, isDispatch: Boolean, - isVararg: Boolean = false + isSpread: Boolean = false ) { val returnArguments = block.returnExpressions() if (returnArguments.isEmpty()) { @@ -157,7 +157,7 @@ private fun Candidate.resolveBlockArgument( isDispatch = false, sink = sink, context = context, - isVararg = isVararg + isSpread = isSpread ) return } @@ -170,7 +170,7 @@ private fun Candidate.resolveBlockArgument( context, isReceiver, isDispatch, - isVararg = isVararg + isSpread = isSpread ) } } @@ -184,7 +184,7 @@ fun Candidate.resolveSubCallArgument( isReceiver: Boolean, isDispatch: Boolean, useNullableArgumentType: Boolean = false, - isVararg: Boolean = false + isSpread: Boolean = false ) { require(argument is FirExpression) val candidate = argument.candidate() ?: return resolvePlainExpressionArgument( @@ -196,7 +196,7 @@ fun Candidate.resolveSubCallArgument( isReceiver, isDispatch, useNullableArgumentType, - isVararg = isVararg + isSpread = isSpread ) /* * It's important to extract type from argument neither from symbol, because of symbol contains @@ -214,7 +214,7 @@ fun Candidate.resolveSubCallArgument( isReceiver, isDispatch, useNullableArgumentType, - isVararg = isVararg + isSpread = isSpread ) } @@ -247,7 +247,7 @@ fun Candidate.resolvePlainExpressionArgument( isReceiver: Boolean, isDispatch: Boolean, useNullableArgumentType: Boolean = false, - isVararg: Boolean = false + isSpread: Boolean = false ) { if (expectedType == null) return @@ -266,7 +266,7 @@ fun Candidate.resolvePlainExpressionArgument( isReceiver, isDispatch, useNullableArgumentType, - isVararg = isVararg + isSpread = isSpread ) } @@ -280,7 +280,7 @@ fun Candidate.resolvePlainArgumentType( isReceiver: Boolean, isDispatch: Boolean, useNullableArgumentType: Boolean = false, - isVararg: Boolean = false + isSpread: Boolean = false ) { val position = if (isReceiver) ConeReceiverConstraintPosition(argument) else ConeArgumentConstraintPosition(argument) @@ -305,7 +305,7 @@ fun Candidate.resolvePlainArgumentType( } checkApplicabilityForArgumentType( - csBuilder, argument, argumentTypeForApplicabilityCheck, expectedType, position, isReceiver, isDispatch, sink, context, isVararg = isVararg + csBuilder, argument, argumentTypeForApplicabilityCheck, expectedType, position, isReceiver, isDispatch, sink, context, isSpread = isSpread ) } @@ -354,16 +354,16 @@ private fun checkApplicabilityForArgumentType( isDispatch: Boolean, sink: CheckerSink, context: ResolutionContext, - isVararg: Boolean = false + isSpread: Boolean = false ) { if (expectedType == null) return var argumentType = captureFromTypeParameterUpperBoundIfNeeded(argumentTypeBeforeCapturing, expectedType, context.session) - if (isVararg) + if (isSpread) if (expectedType.isPrimitiveArray || !expectedType.isNonPrimitiveGenericArray) return argumentType = argumentType.arrayElementType()?.createOutArrayType(createPrimitiveArrayType = false) ?: argumentType - } + fun subtypeError(actualExpectedType: ConeKotlinType): ResolutionDiagnostic { From 7a32a631a9744cc22955f796a8ce7305c27bf2d2 Mon Sep 17 00:00:00 2001 From: BlaBlaHuman Date: Fri, 12 Apr 2024 16:23:06 +0200 Subject: [PATCH 06/16] Revert file, fix bracket --- .../kotlin/fir/resolve/calls/Arguments.kt | 4 ++-- .../jetbrains/kotlin/ir/types/IrTypeUtils.kt | 21 +++++++------------ 2 files changed, 9 insertions(+), 16 deletions(-) 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 0cad81c25a4b3..9830d4df2bf09 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 @@ -359,11 +359,11 @@ private fun checkApplicabilityForArgumentType( if (expectedType == null) return var argumentType = captureFromTypeParameterUpperBoundIfNeeded(argumentTypeBeforeCapturing, expectedType, context.session) - if (isSpread) + if (isSpread) { if (expectedType.isPrimitiveArray || !expectedType.isNonPrimitiveGenericArray) return argumentType = argumentType.arrayElementType()?.createOutArrayType(createPrimitiveArrayType = false) ?: argumentType - + } fun subtypeError(actualExpectedType: ConeKotlinType): ResolutionDiagnostic { 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 b27a0d953852e..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 @@ -9,10 +9,7 @@ import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.ir.IrBuiltIns import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable -import org.jetbrains.kotlin.ir.util.isPrimitiveArray -import org.jetbrains.kotlin.ir.util.render import org.jetbrains.kotlin.types.AbstractTypeChecker -import org.jetbrains.kotlin.types.checker.SimpleClassicTypeSystemContext.extractTypeParameters fun IrClassifierSymbol.superTypes(): List = when (this) { is IrClassSymbol -> owner.superTypes @@ -56,17 +53,8 @@ fun IrType.isNullable(): Boolean = val IrType.isBoxedArray: Boolean get() = classOrNull?.owner?.fqNameWhenAvailable == StandardNames.FqNames.array.toSafe() - fun IrType.getArrayElementType(irBuiltIns: IrBuiltIns): IrType = - if (isPrimitiveArray()) { - println("getArrayElementType primitive") - val classifier = this.classOrNull!! - irBuiltIns.primitiveArrayElementTypes[classifier] - ?: irBuiltIns.unsignedArraysElementTypes[classifier] - ?: throw AssertionError("Primitive array expected: $classifier") - } - else { - println("getArrayElementType boxedarray") + if (isBoxedArray) { when (val argument = (this as IrSimpleType).arguments.singleOrNull()) { is IrTypeProjection -> argument.type @@ -75,6 +63,11 @@ fun IrType.getArrayElementType(irBuiltIns: IrBuiltIns): IrType = null -> error("Unexpected array argument type: null") } + } else { + val classifier = this.classOrNull!! + irBuiltIns.primitiveArrayElementTypes[classifier] + ?: irBuiltIns.unsignedArraysElementTypes[classifier] + ?: throw AssertionError("Primitive array expected: $classifier") } fun IrType.toArrayOrPrimitiveArrayType(irBuiltIns: IrBuiltIns): IrType = @@ -83,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 From 734613ea0f3551ff462f33e7f14497398df9ba66 Mon Sep 17 00:00:00 2001 From: BlaBlaHuman Date: Sun, 14 Apr 2024 12:53:55 +0200 Subject: [PATCH 07/16] Fix argument --- .../src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 9830d4df2bf09..410dc98351d74 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 @@ -475,7 +475,7 @@ internal fun Candidate.resolveArgument( context, isReceiver, false, - isVararg = argument is FirSpreadArgumentExpression + isSpread = argument is FirSpreadArgumentExpression ) } From ddffdadb899389aab533ce7f76ab33633720711d Mon Sep 17 00:00:00 2001 From: BlaBlaHuman Date: Sun, 14 Apr 2024 21:05:54 +0200 Subject: [PATCH 08/16] Update argument type checking --- .../kotlin/fir/types/ConeBuiltinTypeUtils.kt | 4 ---- .../kotlin/fir/resolve/calls/Arguments.kt | 14 +++++++++++--- 2 files changed, 11 insertions(+), 7 deletions(-) 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 9fb6025b0cc68..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,10 +51,6 @@ val ConeKotlinType.isArrayTypeOrNullableArrayType: Boolean get() = isArrayType(i val ConeKotlinType.isNonPrimitiveArray: Boolean get() = this is ConeClassLikeType && lookupTag.classId == StandardClassIds.Array -val ConeKotlinType.isNonPrimitiveGenericArray: Boolean - get() = this is ConeClassLikeType && lookupTag.classId == StandardClassIds.Array && typeArguments.size == 1 - - val ConeKotlinType.isIntArray: Boolean get() = this is ConeClassLikeType && lookupTag.classId == StandardClassIds.primitiveArrayTypeByElementType[StandardClassIds.Int] 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 410dc98351d74..a35ce6f993193 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 @@ -360,9 +360,17 @@ private fun checkApplicabilityForArgumentType( var argumentType = captureFromTypeParameterUpperBoundIfNeeded(argumentTypeBeforeCapturing, expectedType, context.session) if (isSpread) { - if (expectedType.isPrimitiveArray || !expectedType.isNonPrimitiveGenericArray) - return - argumentType = argumentType.arrayElementType()?.createOutArrayType(createPrimitiveArrayType = false) ?: argumentType + argumentType = when { + expectedType.isPrimitiveArray && argumentType.arrayElementType()?.isPrimitive == true -> + argumentType.arrayElementType()?.createArrayType( + createPrimitiveArrayTypeIfPossible = true + ) ?: argumentType + expectedType.isNonPrimitiveArray -> + argumentType.arrayElementType()?.createOutArrayType( + createPrimitiveArrayType = false + ) ?: argumentType + else -> argumentType + } } From 30478daca784af59cb678af38456252533ad59ed Mon Sep 17 00:00:00 2001 From: BlaBlaHuman Date: Tue, 16 Apr 2024 20:38:36 +0200 Subject: [PATCH 09/16] Rewrite type argument retrieval --- .../src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 a35ce6f993193..7f53d7d6a7606 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 @@ -361,12 +361,12 @@ private fun checkApplicabilityForArgumentType( if (isSpread) { argumentType = when { - expectedType.isPrimitiveArray && argumentType.arrayElementType()?.isPrimitive == true -> - argumentType.arrayElementType()?.createArrayType( + expectedType.isPrimitiveArray && argumentType.spreadableCollectionElementType()?.isPrimitive == true -> + argumentType.spreadableCollectionElementType()?.createArrayType( createPrimitiveArrayTypeIfPossible = true ) ?: argumentType expectedType.isNonPrimitiveArray -> - argumentType.arrayElementType()?.createOutArrayType( + argumentType.spreadableCollectionElementType()?.createOutArrayType( createPrimitiveArrayType = false ) ?: argumentType else -> argumentType From d3738c02b4899f4e95f726beeade6bc4271d40e4 Mon Sep 17 00:00:00 2001 From: BlaBlaHuman Date: Tue, 16 Apr 2024 20:38:49 +0200 Subject: [PATCH 10/16] Rewrite type argument retrieval --- .../jetbrains/kotlin/fir/types/ArrayUtils.kt | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) 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 a71cff80d4ad0..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 @@ -43,20 +43,36 @@ fun ConeKotlinType.arrayElementType(checkUnsignedArrays: Boolean = true): ConeKo } } -private fun ConeKotlinType.arrayElementTypeArgument(checkUnsignedArrays: Boolean = true): ConeTypeProjection? { +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 + val classId = type.lookupTag.classId + if (classId == StandardClassIds.Array) { + return type.typeArguments.first() + } val elementType = StandardClassIds.elementTypeByPrimitiveArrayType[classId] ?: runIf(checkUnsignedArrays) { StandardClassIds.elementTypeByUnsignedArrayType[classId] } if (elementType != null) { return elementType.constructClassLikeType(emptyArray(), isNullable = false) } - return null } From b4107c2a7ee3c37b99a2b02a85b249f8f89e5f99 Mon Sep 17 00:00:00 2001 From: BlaBlaHuman Date: Sun, 21 Apr 2024 22:06:57 +0200 Subject: [PATCH 11/16] Check the type equality and not the primitiveness --- .../src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 7f53d7d6a7606..b34a08897c3b9 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 @@ -361,7 +361,7 @@ private fun checkApplicabilityForArgumentType( if (isSpread) { argumentType = when { - expectedType.isPrimitiveArray && argumentType.spreadableCollectionElementType()?.isPrimitive == true -> + expectedType.isPrimitiveArray && (argumentType.spreadableCollectionElementType() == expectedType.spreadableCollectionElementType()) -> argumentType.spreadableCollectionElementType()?.createArrayType( createPrimitiveArrayTypeIfPossible = true ) ?: argumentType From df6b7ccb16f07368069d8b9e97aa68821df51b27 Mon Sep 17 00:00:00 2001 From: BlaBlaHuman Date: Sun, 21 Apr 2024 22:11:28 +0200 Subject: [PATCH 12/16] Optimize code --- .../org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) 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 b34a08897c3b9..0b2cf0ac4ca2e 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 @@ -360,13 +360,16 @@ private fun checkApplicabilityForArgumentType( var argumentType = captureFromTypeParameterUpperBoundIfNeeded(argumentTypeBeforeCapturing, expectedType, context.session) if (isSpread) { + val argumentTypeElement = argumentType.spreadableCollectionElementType() + argumentType = when { - expectedType.isPrimitiveArray && (argumentType.spreadableCollectionElementType() == expectedType.spreadableCollectionElementType()) -> - argumentType.spreadableCollectionElementType()?.createArrayType( + expectedType.isPrimitiveArray + && (argumentTypeElement == expectedType.spreadableCollectionElementType()) -> + argumentTypeElement?.createArrayType( createPrimitiveArrayTypeIfPossible = true ) ?: argumentType expectedType.isNonPrimitiveArray -> - argumentType.spreadableCollectionElementType()?.createOutArrayType( + argumentTypeElement?.createOutArrayType( createPrimitiveArrayType = false ) ?: argumentType else -> argumentType From b48c76c916bfde2552d9bcca6ff90e300b870385 Mon Sep 17 00:00:00 2001 From: BlaBlaHuman Date: Tue, 23 Apr 2024 04:46:45 +0200 Subject: [PATCH 13/16] Fix conditions --- .../src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 0b2cf0ac4ca2e..bb79b107f9605 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 @@ -359,7 +359,7 @@ private fun checkApplicabilityForArgumentType( if (expectedType == null) return var argumentType = captureFromTypeParameterUpperBoundIfNeeded(argumentTypeBeforeCapturing, expectedType, context.session) - if (isSpread) { + if (isSpread && !argumentType.isNullable) { val argumentTypeElement = argumentType.spreadableCollectionElementType() argumentType = when { @@ -486,7 +486,7 @@ internal fun Candidate.resolveArgument( context, isReceiver, false, - isSpread = argument is FirSpreadArgumentExpression + isSpread = argument is FirSpreadArgumentExpression && parameter?.isVararg == true ) } From ff490103ef0ff7ae2961085da0d067820cdfd656 Mon Sep 17 00:00:00 2001 From: BlaBlaHuman Date: Thu, 25 Apr 2024 03:25:44 +0200 Subject: [PATCH 14/16] Rewrite typechecking --- .../kotlin/fir/resolve/calls/Arguments.kt | 25 ++++++------------- .../FirExpressionsResolveTransformer.kt | 3 ++- 2 files changed, 10 insertions(+), 18 deletions(-) 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 bb79b107f9605..81ab750332b69 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 @@ -348,7 +348,7 @@ private fun checkApplicabilityForArgumentType( csBuilder: ConstraintSystemBuilder, argument: FirExpression, argumentTypeBeforeCapturing: ConeKotlinType, - expectedType: ConeKotlinType?, + initialExpectedType: ConeKotlinType?, position: ConstraintPosition, isReceiver: Boolean, isDispatch: Boolean, @@ -356,24 +356,15 @@ private fun checkApplicabilityForArgumentType( context: ResolutionContext, isSpread: Boolean = false ) { - if (expectedType == null) return + var expectedType = initialExpectedType ?: return var argumentType = captureFromTypeParameterUpperBoundIfNeeded(argumentTypeBeforeCapturing, expectedType, context.session) if (isSpread && !argumentType.isNullable) { - val argumentTypeElement = argumentType.spreadableCollectionElementType() - - argumentType = when { - expectedType.isPrimitiveArray - && (argumentTypeElement == expectedType.spreadableCollectionElementType()) -> - argumentTypeElement?.createArrayType( - createPrimitiveArrayTypeIfPossible = true - ) ?: argumentType - expectedType.isNonPrimitiveArray -> - argumentTypeElement?.createOutArrayType( - createPrimitiveArrayType = false - ) ?: argumentType - else -> argumentType - } + argumentType = argumentType.spreadableCollectionElementType()?.also { + expectedType = + expectedType.spreadableCollectionElementType() + ?: error("Could not retrieve expected element type for vararg parameter. Parameter type is ${expectedType.renderReadable()}") + } ?: argumentType } @@ -448,7 +439,6 @@ private fun checkApplicabilityForArgumentType( } - if (!isReceiver) { sink.reportDiagnostic(subtypeError(expectedType)) return @@ -463,6 +453,7 @@ private fun checkApplicabilityForArgumentType( sink.reportDiagnostic(InapplicableWrongReceiver(expectedType, argumentType)) } } + } internal fun Candidate.resolveArgument( 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 66d186278c36e..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 @@ -116,8 +116,9 @@ class SpreadArgumentsCastTransformer(override val session: FirSession, private v annotations.addAll(varargArgumentsExpression.annotations) coneElementTypeOrNull = varargArgumentsExpression.coneElementTypeOrNull arguments.addAll(varargArgumentsExpression.arguments.map { firExpression -> - if (firExpression is FirSpreadArgumentExpression) { + 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 From 2b466f78672aceb6a9d76a71d200dd457658a45a Mon Sep 17 00:00:00 2001 From: BlaBlaHuman Date: Thu, 25 Apr 2024 06:15:54 +0200 Subject: [PATCH 15/16] Add a roselve test for non-array spread arguments --- .../SpreadOnNonArrayCollections.resolve | 228 ++++++++++++++++++ .../kotlin/resolve/ResolveTestGenerated.java | 5 + 2 files changed, 233 insertions(+) create mode 100644 compiler/testData/resolve/varargs/SpreadOnNonArrayCollections.resolve 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"); From c7f57f3bbac9fa1834d722f013ad700431295ba2 Mon Sep 17 00:00:00 2001 From: BlaBlaHuman Date: Tue, 30 Apr 2024 21:55:22 +0200 Subject: [PATCH 16/16] Simplify the code --- .../org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) 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 81ab750332b69..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 @@ -362,8 +362,11 @@ private fun checkApplicabilityForArgumentType( if (isSpread && !argumentType.isNullable) { argumentType = argumentType.spreadableCollectionElementType()?.also { expectedType = - expectedType.spreadableCollectionElementType() - ?: error("Could not retrieve expected element type for vararg parameter. Parameter type is ${expectedType.renderReadable()}") + expectedType.arrayElementType() + ?: error( + "Could not retrieve expected element type for vararg parameter." + + " Parameter type is ${expectedType.renderReadable()}" + ) } ?: argumentType }