From 1649d9774936617d714951428561e546260a575f Mon Sep 17 00:00:00 2001 From: BlaBlaHuman Date: Mon, 18 Mar 2024 12:12:05 +0100 Subject: [PATCH 1/4] Cleanup PrimitiveSpreadBuilders.kt --- .../runtime/kotlin/jvm/internal/PrimitiveSpreadBuilders.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/stdlib/jvm/runtime/kotlin/jvm/internal/PrimitiveSpreadBuilders.kt b/libraries/stdlib/jvm/runtime/kotlin/jvm/internal/PrimitiveSpreadBuilders.kt index f8886a7fa9614..429cd2edee465 100644 --- a/libraries/stdlib/jvm/runtime/kotlin/jvm/internal/PrimitiveSpreadBuilders.kt +++ b/libraries/stdlib/jvm/runtime/kotlin/jvm/internal/PrimitiveSpreadBuilders.kt @@ -6,7 +6,7 @@ package kotlin.jvm.internal public abstract class PrimitiveSpreadBuilder(private val size: Int) { - abstract protected fun T.getSize(): Int + protected abstract fun T.getSize(): Int protected var position: Int = 0 @@ -19,7 +19,7 @@ public abstract class PrimitiveSpreadBuilder(private val size: Int) { protected fun size(): Int { var totalLength = 0 - for (i in 0..size - 1) { + for (i in 0..(private val size: Int) { protected fun toArray(values: T, result: T): T { var dstIndex = 0 var copyValuesFrom = 0 - for (i in 0..size - 1) { + for (i in 0.. Date: Wed, 3 Apr 2024 11:38:16 +0200 Subject: [PATCH 2/4] Some work on the frontend --- .../fir/components/KtFirImportOptimizer.kt | 4 +-- .../fir/components/KtFirReferenceShortener.kt | 4 +-- .../references/FirReferenceResolveHelper.kt | 2 +- .../generators/CallAndReferenceGenerator.kt | 2 +- .../jetbrains/kotlin/fir/types/ArrayUtils.kt | 4 +++ .../kotlin/fir/builder/ConversionUtils.kt | 2 +- .../transformers/FirTypeResolveTransformer.kt | 4 +-- .../resolve/transformers/TransformUtils.kt | 15 ++++----- .../body/resolve/BodyResolveUtils.kt | 2 +- .../org/jetbrains/kotlin/KtSourceElement.kt | 2 +- .../src/org/jetbrains/kotlin/ir/IrBuiltIns.kt | 2 ++ .../jetbrains/kotlin/ir/types/IrTypeUtils.kt | 33 ++++++++++--------- 12 files changed, 40 insertions(+), 36 deletions(-) diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirImportOptimizer.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirImportOptimizer.kt index ebb71cea3276e..b425f64d13df0 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirImportOptimizer.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirImportOptimizer.kt @@ -477,14 +477,14 @@ private sealed interface TypeQualifier { private val FirResolvedTypeRef.isPresentInSource: Boolean get() = when (source?.kind) { is KtRealSourceElementKind -> { - val isArrayFromVararg = delegatedTypeRef?.source?.kind is KtFakeSourceElementKind.ArrayTypeFromVarargParameter; + val isArrayFromVararg = delegatedTypeRef?.source?.kind is KtFakeSourceElementKind.UnderlyingTypeFromVarargParameter; // type ref with delegated type ref with such source kind is NOT directly present in the source, so we ignore it !isArrayFromVararg } // type ref with such source kind is explicitly present in the source, so we want to see it - is KtFakeSourceElementKind.ArrayTypeFromVarargParameter -> true + is KtFakeSourceElementKind.UnderlyingTypeFromVarargParameter -> true else -> false } diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirReferenceShortener.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirReferenceShortener.kt index 95722af82cbf7..07dd5fadbbd00 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirReferenceShortener.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirReferenceShortener.kt @@ -539,10 +539,10 @@ private class ElementsToShortenCollector( get() { val sourcePsi = when { // array type for vararg parameters is not present in the code, so no need to handle it - delegatedTypeRef?.source?.kind == KtFakeSourceElementKind.ArrayTypeFromVarargParameter -> null + delegatedTypeRef?.source?.kind == KtFakeSourceElementKind.UnderlyingTypeFromVarargParameter -> null // but the array's underlying type is present with a fake source, and needs to be handled - source?.kind == KtFakeSourceElementKind.ArrayTypeFromVarargParameter -> psi + source?.kind == KtFakeSourceElementKind.UnderlyingTypeFromVarargParameter -> psi else -> realPsi } diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/references/FirReferenceResolveHelper.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/references/FirReferenceResolveHelper.kt index a8e3c7c309dcc..e5e4c8940821d 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/references/FirReferenceResolveHelper.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/references/FirReferenceResolveHelper.kt @@ -79,7 +79,7 @@ internal object FirReferenceResolveHelper { } private fun FirResolvedTypeRef.getDeclaredType() = - if (this.delegatedTypeRef?.source?.kind == KtFakeSourceElementKind.ArrayTypeFromVarargParameter) type.arrayElementType() + if (this.delegatedTypeRef?.source?.kind == KtFakeSourceElementKind.UnderlyingTypeFromVarargParameter) type.arrayElementType() else type private fun ClassId.toTargetPsi( diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/CallAndReferenceGenerator.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/CallAndReferenceGenerator.kt index ab4da19d91d4e..84802e41ff488 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/CallAndReferenceGenerator.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/CallAndReferenceGenerator.kt @@ -1089,7 +1089,7 @@ class CallAndReferenceGenerator( if (parameter?.returnTypeRef is FirResolvedTypeRef) { // Java type case (from annotations) val parameterType = parameter.returnTypeRef.coneType - val unwrappedParameterType = if (parameter.isVararg) parameterType.arrayElementType()!! else parameterType + val unwrappedParameterType = if (parameter.isVararg) parameterType.typeArguments.first().type!! else parameterType val samFunctionType = getFunctionTypeForPossibleSamType(unwrappedParameterType) irArgument = irArgument.applySuspendConversionIfNeeded(argument, samFunctionType ?: unwrappedParameterType) irArgument = irArgument.applySamConversionIfNeeded(argument, parameter) 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..476e39a76dd8a 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 @@ -35,6 +35,10 @@ fun ConeTypeProjection.createArrayType(nullable: Boolean = false, createPrimitiv return StandardClassIds.Array.constructClassLikeType(arrayOf(this), nullable) } +fun ConeTypeProjection.createListType(nullable: Boolean = false): ConeClassLikeType { + return StandardClassIds.List.constructClassLikeType(arrayOf(this), nullable) +} + fun ConeKotlinType.arrayElementType(checkUnsignedArrays: Boolean = true): ConeKotlinType? { return when (val argument = arrayElementTypeArgument(checkUnsignedArrays)) { is ConeKotlinTypeProjection -> argument.type diff --git a/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/ConversionUtils.kt b/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/ConversionUtils.kt index 5c3e1aa741354..deb043dfac004 100644 --- a/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/ConversionUtils.kt +++ b/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/ConversionUtils.kt @@ -715,6 +715,6 @@ fun FirErrorTypeRef.wrapIntoArray(): FirResolvedTypeRef { return buildResolvedTypeRef { source = typeRef.source type = StandardClassIds.Array.constructClassLikeType(arrayOf(ConeKotlinTypeProjectionOut(typeRef.coneType))) - delegatedTypeRef = typeRef.copyWithNewSourceKind(KtFakeSourceElementKind.ArrayTypeFromVarargParameter) + delegatedTypeRef = typeRef.copyWithNewSourceKind(KtFakeSourceElementKind.UnderlyingTypeFromVarargParameter) } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirTypeResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirTypeResolveTransformer.kt index 81795e3e6fafe..804a4b0b35b72 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirTypeResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirTypeResolveTransformer.kt @@ -208,8 +208,8 @@ open class FirTypeResolveTransformer( .transformAnnotations(this, data) if (property.isFromVararg == true) { - property.transformTypeToArrayType() - property.backingField?.transformTypeToArrayType() + property.transformTypeToUnderlyingType() + property.backingField?.transformTypeToUnderlyingType() setAccessorTypesByPropertyType(property) } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/TransformUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/TransformUtils.kt index cb40dfd79a89f..ce80e1d4696ec 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/TransformUtils.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/TransformUtils.kt @@ -10,35 +10,32 @@ import org.jetbrains.kotlin.fir.copyWithNewSourceKind import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.declarations.FirValueParameter -import org.jetbrains.kotlin.fir.types.ConeKotlinTypeProjectionOut -import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef +import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef -import org.jetbrains.kotlin.fir.types.coneType -import org.jetbrains.kotlin.fir.types.createArrayType internal fun FirValueParameter.transformVarargTypeToArrayType() { if (isVararg) { - this.transformTypeToArrayType() + this.transformTypeToUnderlyingType() } } -internal fun FirCallableDeclaration.transformTypeToArrayType() { +internal fun FirCallableDeclaration.transformTypeToUnderlyingType() { val returnTypeRef = this.returnTypeRef require(returnTypeRef is FirResolvedTypeRef) // If the delegated type is already resolved, it means we have already created a resolved array type for this vararg type declaration. // This is because in the buildResolvedTypeRef call below, we set the delegated type ref to the previous (non-vararg) resolved type ref. if (returnTypeRef.delegatedTypeRef is FirResolvedTypeRef && - returnTypeRef.delegatedTypeRef?.source?.kind == KtFakeSourceElementKind.ArrayTypeFromVarargParameter + returnTypeRef.delegatedTypeRef?.source?.kind == KtFakeSourceElementKind.UnderlyingTypeFromVarargParameter ) return val returnType = returnTypeRef.coneType replaceReturnTypeRef( buildResolvedTypeRef { source = returnTypeRef.source - type = ConeKotlinTypeProjectionOut(returnType).createArrayType() + type = ConeKotlinTypeProjectionOut(returnType).createListType() annotations += returnTypeRef.annotations // ? do we really need replacing source of nested delegatedTypeRef ? - delegatedTypeRef = returnTypeRef.copyWithNewSourceKind(KtFakeSourceElementKind.ArrayTypeFromVarargParameter) + delegatedTypeRef = returnTypeRef.copyWithNewSourceKind(KtFakeSourceElementKind.UnderlyingTypeFromVarargParameter) } ) } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/BodyResolveUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/BodyResolveUtils.kt index 48d6ee375aa00..0d27f1ab8e62a 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/BodyResolveUtils.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/BodyResolveUtils.kt @@ -39,7 +39,7 @@ internal fun remapArgumentsWithVararg( // Create a FirVarargArgumentExpression for the vararg arguments. // The order of arguments in the mapping must be preserved for FIR2IR, hence we have to find where the vararg arguments end. // FIR2IR uses the mapping order to determine if arguments need to be reordered. - val varargElementType = varargArrayType.arrayElementType()?.approximateIntegerLiteralType() + val varargElementType = varargArrayType.typeArguments.first().type?.approximateIntegerLiteralType() val argumentList = argumentMapping.keys.toList() var indexAfterVarargs = argumentList.size val newArgumentMapping = linkedMapOf() diff --git a/compiler/frontend.common/src/org/jetbrains/kotlin/KtSourceElement.kt b/compiler/frontend.common/src/org/jetbrains/kotlin/KtSourceElement.kt index 0a437e643e5f5..5731610284b3b 100644 --- a/compiler/frontend.common/src/org/jetbrains/kotlin/KtSourceElement.kt +++ b/compiler/frontend.common/src/org/jetbrains/kotlin/KtSourceElement.kt @@ -166,7 +166,7 @@ sealed class KtFakeSourceElementKind(final override val shouldSkipErrorTypeRepor object DataClassGeneratedMembers : KtFakeSourceElementKind(shouldSkipErrorTypeReporting = true) // (vararg x: Int) --> (x: Array) where array type ref has a fake source kind - object ArrayTypeFromVarargParameter : KtFakeSourceElementKind() + object UnderlyingTypeFromVarargParameter : KtFakeSourceElementKind() // val (a,b) = x --> val a = x.component1(); val b = x.component2() // where componentN calls will have the fake source elements refer to the corresponding KtDestructuringDeclarationEntry diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/IrBuiltIns.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/IrBuiltIns.kt index 4e314e485e4b7..33c0f08c233d9 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/IrBuiltIns.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/IrBuiltIns.kt @@ -133,6 +133,8 @@ abstract class IrBuiltIns { abstract val primitiveArrayElementTypes: Map abstract val primitiveArrayForType: Map +// abstract val listElementTypes: Map + abstract val unsignedTypesToUnsignedArrays: Map abstract val unsignedArraysElementTypes: Map 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..12ca47f52484b 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 @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.ir.IrBuiltIns import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable import org.jetbrains.kotlin.types.AbstractTypeChecker +import org.jetbrains.kotlin.types.checker.SimpleClassicTypeSystemContext.typeConstructor fun IrClassifierSymbol.superTypes(): List = when (this) { is IrClassSymbol -> owner.superTypes @@ -53,22 +54,22 @@ fun IrType.isNullable(): Boolean = val IrType.isBoxedArray: Boolean get() = classOrNull?.owner?.fqNameWhenAvailable == StandardNames.FqNames.array.toSafe() -fun IrType.getArrayElementType(irBuiltIns: IrBuiltIns): IrType = - if (isBoxedArray) { - when (val argument = (this as IrSimpleType).arguments.singleOrNull()) { - is IrTypeProjection -> - argument.type - is IrStarProjection -> - irBuiltIns.anyNType - 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.getArrayElementType(irBuiltIns: IrBuiltIns): IrType = this.getClass()?.typeConstructorParameters?.first()?.defaultType ?: error("getArrayElementType") +// if (isBoxedArray) { +// when (val argument = (this as IrSimpleType).arguments.singleOrNull()) { +// is IrTypeProjection -> +// argument.type +// is IrStarProjection -> +// irBuiltIns.anyNType +// 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 = if (isPrimitiveType()) { From 57516cc611900f7cbe458428b72479265fad140d Mon Sep 17 00:00:00 2001 From: BlaBlaHuman Date: Sun, 7 Apr 2024 23:14:56 +0200 Subject: [PATCH 3/4] Fix `getArrayElementType` --- .../jetbrains/kotlin/ir/types/IrTypeUtils.kt | 37 ++++++++++--------- 1 file changed, 20 insertions(+), 17 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 12ca47f52484b..7117cee4435a9 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,8 +9,8 @@ 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.types.AbstractTypeChecker -import org.jetbrains.kotlin.types.checker.SimpleClassicTypeSystemContext.typeConstructor fun IrClassifierSymbol.superTypes(): List = when (this) { is IrClassSymbol -> owner.superTypes @@ -54,22 +54,25 @@ fun IrType.isNullable(): Boolean = val IrType.isBoxedArray: Boolean get() = classOrNull?.owner?.fqNameWhenAvailable == StandardNames.FqNames.array.toSafe() -fun IrType.getArrayElementType(irBuiltIns: IrBuiltIns): IrType = this.getClass()?.typeConstructorParameters?.first()?.defaultType ?: error("getArrayElementType") -// if (isBoxedArray) { -// when (val argument = (this as IrSimpleType).arguments.singleOrNull()) { -// is IrTypeProjection -> -// argument.type -// is IrStarProjection -> -// irBuiltIns.anyNType -// 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.getArrayElementType(irBuiltIns: IrBuiltIns): IrType = + if (isBoxedArray) { + when (val argument = (this as IrSimpleType).arguments.singleOrNull()) { + is IrTypeProjection -> + argument.type + is IrStarProjection -> + irBuiltIns.anyNType + null -> + error("Unexpected array argument type: null") + } + } else if (isPrimitiveArray()) { + val classifier = this.classOrNull!! + irBuiltIns.primitiveArrayElementTypes[classifier] + ?: irBuiltIns.unsignedArraysElementTypes[classifier] + ?: throw AssertionError("Primitive array expected: $classifier") + } else { + this.getClass()?.typeConstructorParameters?.first()?.defaultType ?: error("Expected collection type") + } fun IrType.toArrayOrPrimitiveArrayType(irBuiltIns: IrBuiltIns): IrType = if (isPrimitiveType()) { From 82107f7955ab82023a87eca589c605d88fb1b4de Mon Sep 17 00:00:00 2001 From: BlaBlaHuman Date: Mon, 8 Apr 2024 14:28:36 +0200 Subject: [PATCH 4/4] Some work --- .../kotlin/fir/backend/IrBuiltInsOverFir.kt | 11 + .../jetbrains/kotlin/fir/types/ArrayUtils.kt | 12 +- .../resolve/transformers/TransformUtils.kt | 2 +- .../jetbrains/kotlin/backend/common/ir/Ir.kt | 3 + .../backend/jvm/lower/VarargLowering.kt | 12 +- .../kotlin/backend/jvm/ir/IrSpreadBuilder.kt | 189 ++++++++++++++++++ .../descriptors/IrBuiltInsOverDescriptors.kt | 10 + .../src/org/jetbrains/kotlin/ir/IrBuiltIns.kt | 2 + .../jetbrains/kotlin/ir/types/IrTypeUtils.kt | 17 +- .../jvm/internal/IterableSpreadBuilder.kt | 50 +++++ 10 files changed, 285 insertions(+), 23 deletions(-) create mode 100644 compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/IrSpreadBuilder.kt create mode 100644 libraries/stdlib/jvm/runtime/kotlin/jvm/internal/IterableSpreadBuilder.kt diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/IrBuiltInsOverFir.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/IrBuiltInsOverFir.kt index 097abec1ee139..8640e72781868 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/IrBuiltInsOverFir.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/IrBuiltInsOverFir.kt @@ -477,6 +477,17 @@ class IrBuiltInsOverFir( findFunctions(kotlinPackage, Name.identifier("arrayOf")).distinct().single() } + override val listOf: IrSimpleFunctionSymbol by lazy { + findFunctions(StandardClassIds.BASE_COLLECTIONS_PACKAGE, Name.identifier("listOf")).distinct() + .single { it.descriptor.valueParameters.getOrNull(0)?.varargElementType != null } + } + + override val mutableListOf: IrSimpleFunctionSymbol by lazy { + findFunctions(StandardClassIds.BASE_COLLECTIONS_PACKAGE, Name.identifier("mutableListOf")).distinct() + .single { it.descriptor.valueParameters.size == 0 } + } + + override fun getNonBuiltInFunctionsByExtensionReceiver( name: Name, vararg packageNameSegments: String, 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 476e39a76dd8a..66a3ea7a48ce7 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 @@ -35,8 +35,8 @@ fun ConeTypeProjection.createArrayType(nullable: Boolean = false, createPrimitiv return StandardClassIds.Array.constructClassLikeType(arrayOf(this), nullable) } -fun ConeTypeProjection.createListType(nullable: Boolean = false): ConeClassLikeType { - return StandardClassIds.List.constructClassLikeType(arrayOf(this), nullable) +fun ConeTypeProjection.createIterableType(nullable: Boolean = false): ConeClassLikeType { + return StandardClassIds.MutableList.constructClassLikeType(arrayOf(this), nullable) } fun ConeKotlinType.arrayElementType(checkUnsignedArrays: Boolean = true): ConeKotlinType? { @@ -49,10 +49,7 @@ fun ConeKotlinType.arrayElementType(checkUnsignedArrays: Boolean = true): ConeKo 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] } @@ -60,7 +57,8 @@ private fun ConeKotlinType.arrayElementTypeArgument(checkUnsignedArrays: Boolean return elementType.constructClassLikeType(emptyArray(), isNullable = false) } - return null + val classId = type.lookupTag.classId + return type.typeArguments.firstOrNull() } fun ConeKotlinType.varargElementType(): ConeKotlinType { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/TransformUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/TransformUtils.kt index ce80e1d4696ec..e5d707f93e615 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/TransformUtils.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/TransformUtils.kt @@ -32,7 +32,7 @@ internal fun FirCallableDeclaration.transformTypeToUnderlyingType() { replaceReturnTypeRef( buildResolvedTypeRef { source = returnTypeRef.source - type = ConeKotlinTypeProjectionOut(returnType).createListType() + type = ConeKotlinTypeProjectionOut(returnType).createIterableType() annotations += returnTypeRef.annotations // ? do we really need replacing source of nested delegatedTypeRef ? delegatedTypeRef = returnTypeRef.copyWithNewSourceKind(KtFakeSourceElementKind.UnderlyingTypeFromVarargParameter) diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/Ir.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/Ir.kt index a0f0e1ae29a6d..386a80f06f43b 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/Ir.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/Ir.kt @@ -112,6 +112,9 @@ open class BuiltinSymbolsBase(val irBuiltIns: IrBuiltIns, private val symbolTabl val arrayOf: IrSimpleFunctionSymbol get() = irBuiltIns.arrayOf val arrayOfNulls: IrSimpleFunctionSymbol get() = irBuiltIns.arrayOfNulls + val listOf: IrSimpleFunctionSymbol get() = irBuiltIns.listOf + val mutableListOf: IrSimpleFunctionSymbol get() = irBuiltIns.mutableListOf + val array get() = irBuiltIns.arrayClass val byteArray get() = irBuiltIns.byteArray diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/VarargLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/VarargLowering.kt index 25acc9665a838..b4fd42f52da46 100644 --- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/VarargLowering.kt +++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/VarargLowering.kt @@ -9,10 +9,7 @@ import org.jetbrains.kotlin.backend.common.FileLoweringPass import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase import org.jetbrains.kotlin.backend.jvm.JvmBackendContext -import org.jetbrains.kotlin.backend.jvm.ir.IrArrayBuilder -import org.jetbrains.kotlin.backend.jvm.ir.createJvmIrBuilder -import org.jetbrains.kotlin.backend.jvm.ir.irArray -import org.jetbrains.kotlin.backend.jvm.ir.irArrayOf +import org.jetbrains.kotlin.backend.jvm.ir.* import org.jetbrains.kotlin.builtins.PrimitiveType import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.builtins.UnsignedType @@ -64,10 +61,11 @@ internal class VarargLowering(val context: JvmBackendContext) : FileLoweringPass return expression } - override fun visitVararg(expression: IrVararg): IrExpression = - createBuilder(expression.startOffset, expression.endOffset).irArray(expression.type) { addVararg(expression) } + override fun visitVararg(expression: IrVararg): IrExpression { + return createBuilder(expression.startOffset, expression.endOffset).irSpreadArray(expression.type) { addVararg(expression) } + } - private fun IrArrayBuilder.addVararg(expression: IrVararg) { + private fun IrSpreadBuilder.addVararg(expression: IrVararg) { loop@ for (element in expression.elements) { when (element) { is IrExpression -> +element.transform(this@VarargLowering, null) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/IrSpreadBuilder.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/IrSpreadBuilder.kt new file mode 100644 index 0000000000000..d52ba674b36d9 --- /dev/null +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/IrSpreadBuilder.kt @@ -0,0 +1,189 @@ +/* + * Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.backend.jvm.ir + +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +import org.jetbrains.kotlin.backend.jvm.unboxInlineClass +import org.jetbrains.kotlin.builtins.PrimitiveType +import org.jetbrains.kotlin.ir.builders.* +import org.jetbrains.kotlin.ir.expressions.IrConstructorCall +import org.jetbrains.kotlin.ir.expressions.IrExpression +import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression +import org.jetbrains.kotlin.ir.expressions.IrGetValue +import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl +import org.jetbrains.kotlin.ir.types.* +import org.jetbrains.kotlin.ir.util.* + +inline fun JvmIrBuilder.irSpreadArray(arrayType: IrType, block: IrSpreadBuilder.() -> Unit): IrExpression = + IrSpreadBuilder(this, arrayType).apply { block() }.build() + +fun JvmIrBuilder.irSpreadArrayOf(arrayType: IrType, elements: List = listOf()): IrExpression = + irSpreadArray(arrayType) { elements.forEach { +it } } + +private class IrSpreadElement(val expression: IrExpression, val isSpread: Boolean) + +class IrSpreadBuilder(val builder: JvmIrBuilder, val collectionType: IrType) { + // The unwrapped element type + val elementType = collectionType.getArrayElementType(builder.context.irBuiltIns) + +// +// val isPrimitive = elementType.isPrimitiveType() || elementType.isNullablePrimitiveType() +// +// val arrayType = if (collectionType.isBoxedArray || collectionType.isPrimitiveArray()) collectionType else elementType.toArrayOrPrimitiveArrayType(builder.irSymbols.irBuiltIns) +// +// // We build unboxed arrays for inline classes (UIntArray, etc) by first building +// // an unboxed array of the underlying primitive type, then coercing the result +// // to the correct type. +// val unwrappedArrayType = arrayType.unboxInlineClass() +// +// // Check if the array type is an inline class wrapper (UIntArray, etc.) +// val isUnboxedInlineClassArray +// get() = collectionType !== unwrappedArrayType + + private val elements: MutableList = mutableListOf() + + private val hasSpread + get() = elements.any { it.isSpread } + + operator fun IrExpression.unaryPlus() = add(this) + fun add(expression: IrExpression) = elements.add(IrSpreadElement(expression, false)) + + fun addSpread(expression: IrExpression) = elements.add(IrSpreadElement(expression, true)) + + fun build(): IrExpression { + println("irSpreadArrayBuilder build") +// println(unwrappedArrayType.render()) + println(collectionType.render()) + println(elementType.render()) + println(elementType.classOrNull) + println(elementType.classOrNull?.defaultType) +// println(isPrimitive) +// println(isUnboxedInlineClassArray) +// println(unwrappedArrayType.render()) +// println(arrayType.render()) + val array = when { + elements.isEmpty() -> newArray(0) + !hasSpread -> buildSimpleArray() + elements.size == 1 -> copyArray(elements.single().expression) + else -> buildComplexArray() + } + return coerce(array, collectionType) + } + + // Construct a new array of the specified size + private fun newArray(size: Int) = newArray(builder.irInt(size)) + + private fun newArray(size: IrExpression): IrExpression { +// val arrayConstructor = if (unwrappedArrayType.isBoxedArray) +// builder.irSymbols.arrayOfNulls +// else +// unwrappedArrayType.classOrNull!!.constructors.single { it.owner.valueParameters.size == 1 } +// +// println("newArray element type ${elementType.render()}") +// println("newArray array type ${unwrappedArrayType.render()}") + + val arrayConstructor = builder.irSymbols.mutableListOf + println("spread newArray element type ${collectionType.render()}") + return builder.irCall(arrayConstructor, collectionType).apply { + if (typeArgumentsCount != 0) + putTypeArgument(0, elementType) + } + } + + // Build an array without spreads + private fun buildSimpleArray(): IrExpression = + builder.irBlock { + val result = irTemporary(newArray(elements.size)) + + val set = builder.irSymbols.mutableList.functions.single { it.owner.name.asString() == "set" } + + for ((index, element) in elements.withIndex()) { + +irCall(set).apply { + dispatchReceiver = irGet(result) + putValueArgument(0, irInt(index)) + putValueArgument(1, coerce(element.expression, elementType)) + } + } + + +irGet(result) + } + + // Copy a single spread expression, unless it refers to a newly constructed array. + private fun copyArray(spread: IrExpression): IrExpression { +// if (spread is IrConstructorCall || +// (spread is IrFunctionAccessExpression && spread.symbol == builder.irSymbols.arrayOfNulls)) +// return spread + + return builder.irBlock { + val spreadVar = if (spread is IrGetValue) spread.symbol.owner else irTemporary(spread) + val size = collectionType.classOrNull!!.getPropertyGetter("size")!! +// val arrayCopyOf = builder.irSymbols.list.functions.single { it.owner.name.asString() == "toMutableList" } + // TODO consider using System.arraycopy if the requested array type is non-generic. + +coerce(irGet(spreadVar), collectionType) +// +irCall(arrayCopyOf).apply { +// putValueArgument(0, coerce(irGet(spreadVar), collectionType)) +//// putValueArgument(1, irCall(size).apply { dispatchReceiver = irGet(spreadVar) }) +// } + } + } + + // Build an array containing spread expressions. + private fun buildComplexArray(): IrExpression { + val spreadBuilder = if (unwrappedArrayType.isBoxedArray) + builder.irSymbols.spreadBuilder + else + builder.irSymbols.primitiveSpreadBuilders.getValue(elementType) + + val addElement = spreadBuilder.functions.single { it.owner.name.asString() == "add" } + val addSpread = spreadBuilder.functions.single { it.owner.name.asString() == "addSpread" } + val toArray = spreadBuilder.functions.single { it.owner.name.asString() == "toArray" } + + return builder.irBlock { + val spreadBuilderVar = irTemporary(irCallConstructor(spreadBuilder.constructors.single(), listOf()).apply { + putValueArgument(0, irInt(elements.size)) + }) + + for (element in elements) { + +irCall(if (element.isSpread) addSpread else addElement).apply { + dispatchReceiver = irGet(spreadBuilderVar) + putValueArgument(0, coerce(element.expression, if (element.isSpread) unwrappedArrayType else elementType)) + } + } + + val toArrayCall = irCall(toArray).apply { + dispatchReceiver = irGet(spreadBuilderVar) + if (unwrappedArrayType.isBoxedArray) { + val size = spreadBuilder.functions.single { it.owner.name.asString() == "size" } + putValueArgument(0, irCall(builder.irSymbols.arrayOfNulls, arrayType).apply { + putTypeArgument(0, elementType) + putValueArgument(0, irCall(size).apply { + dispatchReceiver = irGet(spreadBuilderVar) + }) + }) + } + } + + if (unwrappedArrayType.isBoxedArray) + +builder.irImplicitCast(toArrayCall, unwrappedArrayType) + else + +toArrayCall + } + } + + // Coerce expression to irType if we are working with an inline class array type + private fun coerce(expression: IrExpression, irType: IrType): IrExpression = + if (true) + builder.irCall(builder.irSymbols.unsafeCoerceIntrinsic, irType).apply { + putTypeArgument(0, expression.type) + putTypeArgument(1, irType) + putValueArgument(0, expression) + } + else expression +} diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/descriptors/IrBuiltInsOverDescriptors.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/descriptors/IrBuiltInsOverDescriptors.kt index 22f3292765eb5..f315d45886edc 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/descriptors/IrBuiltInsOverDescriptors.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/descriptors/IrBuiltInsOverDescriptors.kt @@ -523,6 +523,16 @@ class IrBuiltInsOverDescriptors( it.descriptor.valueParameters.size == 1 && it.descriptor.valueParameters[0].varargElementType != null } + override val listOf = findFunctions(Name.identifier("listOf")).first { + it.descriptor.extensionReceiverParameter == null && it.descriptor.dispatchReceiverParameter == null && + it.descriptor.valueParameters.size == 1 && it.descriptor.valueParameters[0].varargElementType != null + } + + override val mutableListOf = findFunctions(Name.identifier("mutableListOf")).first { + it.descriptor.extensionReceiverParameter == null && it.descriptor.dispatchReceiverParameter == null && + it.descriptor.valueParameters.size == 0 + } + override val arrayOfNulls = findFunctions(Name.identifier("arrayOfNulls")).first { it.descriptor.extensionReceiverParameter == null && it.descriptor.dispatchReceiverParameter == null && it.descriptor.valueParameters.size == 1 && KotlinBuiltIns.isInt(it.descriptor.valueParameters[0].type) diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/IrBuiltIns.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/IrBuiltIns.kt index 33c0f08c233d9..e16a0ff071025 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/IrBuiltIns.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/IrBuiltIns.kt @@ -169,6 +169,8 @@ abstract class IrBuiltIns { abstract val arrayOf: IrSimpleFunctionSymbol abstract val arrayOfNulls: IrSimpleFunctionSymbol + abstract val listOf: IrSimpleFunctionSymbol + abstract val mutableListOf: IrSimpleFunctionSymbol abstract val linkageErrorSymbol: IrSimpleFunctionSymbol 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 7117cee4435a9..75744a83fcc1c 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 @@ -56,7 +56,15 @@ val IrType.isBoxedArray: Boolean 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 @@ -65,13 +73,6 @@ fun IrType.getArrayElementType(irBuiltIns: IrBuiltIns): IrType = null -> error("Unexpected array argument type: null") } - } else if (isPrimitiveArray()) { - val classifier = this.classOrNull!! - irBuiltIns.primitiveArrayElementTypes[classifier] - ?: irBuiltIns.unsignedArraysElementTypes[classifier] - ?: throw AssertionError("Primitive array expected: $classifier") - } else { - this.getClass()?.typeConstructorParameters?.first()?.defaultType ?: error("Expected collection type") } fun IrType.toArrayOrPrimitiveArrayType(irBuiltIns: IrBuiltIns): IrType = diff --git a/libraries/stdlib/jvm/runtime/kotlin/jvm/internal/IterableSpreadBuilder.kt b/libraries/stdlib/jvm/runtime/kotlin/jvm/internal/IterableSpreadBuilder.kt new file mode 100644 index 0000000000000..d5b756256d3e2 --- /dev/null +++ b/libraries/stdlib/jvm/runtime/kotlin/jvm/internal/IterableSpreadBuilder.kt @@ -0,0 +1,50 @@ +/* + * Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package kotlin.jvm.internal + +import java.util.* +import kotlin.collections.ArrayList + +public class IterableSpreadBuilder { + private var list: MutableList = mutableListOf() + + public fun addSpread(container: Any?) { + if (container == null) return + + if (container is Array<*> && container.isArrayOf()) { + if (container.size > 0) { + (container as? Array)?.toCollection(list) + } + } else if (container is Collection<*>) { + if (container.size > 0) { + (container as? Collection)?.toCollection(list) + } + } else if (container is Iterable<*>) { + for (element in container) { + list.add(element as T) + } + } else if (container is Iterator<*>) { + val iterator = container + while (iterator.hasNext()) { + list.add(iterator.next()!! as T) + } + } else { + throw UnsupportedOperationException("Don't know how to spread " + container.javaClass) + } + } + + public fun size(): Int { + return list.size + } + + public fun add(element: T) { + list.add(element) + } + + public fun toArray(): MutableList { + return list + } +} \ No newline at end of file