diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ToArrayLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ToArrayLowering.kt index 0a6a9c462a0..af475f063fc 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ToArrayLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ToArrayLowering.kt @@ -6,42 +6,29 @@ package org.jetbrains.kotlin.backend.jvm.lower import org.jetbrains.kotlin.backend.common.ClassLoweringPass -import org.jetbrains.kotlin.backend.common.descriptors.KnownClassDescriptor -import org.jetbrains.kotlin.backend.common.descriptors.KnownPackageFragmentDescriptor +import org.jetbrains.kotlin.backend.common.descriptors.* import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.backend.jvm.codegen.isJvmInterface -import org.jetbrains.kotlin.builtins.KotlinBuiltIns -import org.jetbrains.kotlin.codegen.isGenericToArray -import org.jetbrains.kotlin.codegen.isNonGenericToArray -import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor -import org.jetbrains.kotlin.descriptors.Modality -import org.jetbrains.kotlin.descriptors.SourceElement -import org.jetbrains.kotlin.descriptors.Visibilities -import org.jetbrains.kotlin.descriptors.annotations.Annotations -import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl -import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl -import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl -import org.jetbrains.kotlin.incremental.components.NoLookupLocation +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.impl.EmptyPackageFragmentDescriptor import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.builders.irBlockBody import org.jetbrains.kotlin.ir.builders.irCall import org.jetbrains.kotlin.ir.builders.irReturn -import org.jetbrains.kotlin.ir.declarations.IrClass -import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl +import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.declarations.impl.* import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl -import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl -import org.jetbrains.kotlin.ir.types.toIrType -import org.jetbrains.kotlin.ir.util.createParameterDeclarations -import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor +import org.jetbrains.kotlin.ir.symbols.IrClassSymbol +import org.jetbrains.kotlin.ir.symbols.impl.* +import org.jetbrains.kotlin.ir.types.* +import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.resolve.DescriptorUtils.isSubclass -import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns -import org.jetbrains.kotlin.resolve.descriptorUtil.getAllSuperclassesWithoutAny import org.jetbrains.kotlin.types.Variance +import org.jetbrains.kotlin.utils.DFS internal val toArrayPhase = makeIrFilePhase( ::ToArrayLowering, @@ -54,118 +41,93 @@ private class ToArrayLowering(private val context: JvmBackendContext) : ClassLow override fun lower(irClass: IrClass) { if (irClass.isJvmInterface) return - val descriptor = irClass.descriptor + val irBuiltIns = context.irBuiltIns - val builtIns = descriptor.builtIns - if (!isSubclass(descriptor, builtIns.collection)) return + if (!irClass.isCollectionSubClass()) return - if (descriptor.getAllSuperclassesWithoutAny().any { classDescriptor -> - classDescriptor !is JavaClassDescriptor && isSubclass( - classDescriptor, - builtIns.collection - ) - }) { - return - } + if (irClass.hasSuperClass { + it != irClass && + it.isClass && + it.origin != IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB && + it.isCollectionSubClass() + }) return val toArrayName = Name.identifier("toArray") - val functions = descriptor.defaultType.memberScope.getContributedFunctions( - toArrayName, NoLookupLocation.FROM_BACKEND - ) + val genericToArray = irClass.declarations.find { it.isGenericToArray() } + val nonGenericToArray = irClass.declarations.find { it.isNonGenericToArray() } - val genericToArray = functions.firstOrNull { it.isGenericToArray() } - val nonGenericToArray = functions.firstOrNull { it.isNonGenericToArray() } - val arrayType = builtIns.getArrayType(Variance.INVARIANT, builtIns.anyType) if (genericToArray == null) { - val toArrayDescriptor = SimpleFunctionDescriptorImpl.create( - irClass.descriptor, org.jetbrains.kotlin.descriptors.annotations.Annotations.EMPTY, - toArrayName, CallableMemberDescriptor.Kind.SYNTHESIZED, SourceElement.NO_SOURCE - ) - toArrayDescriptor.initialize( - null, irClass.descriptor.thisAsReceiverParameter, emptyList(), emptyList(), - arrayType, Modality.OPEN, Visibilities.PUBLIC - ) - - val toArrayUtilDescriptor = createToArrayUtilDescriptor(builtIns, false) - val toArrayType = toArrayUtilDescriptor.returnType!!.toIrType()!! - - val irFunction = IrFunctionImpl( - UNDEFINED_OFFSET, - UNDEFINED_OFFSET, + val typeParameterDescriptor = WrappedTypeParameterDescriptor() + val typeParameter = IrTypeParameterImpl( + UNDEFINED_OFFSET, UNDEFINED_OFFSET, JvmLoweredDeclarationOrigin.TO_ARRAY, - toArrayDescriptor, - returnType = toArrayType - ) - irFunction.createParameterDeclarations() - - irFunction.body = context.createIrBuilder(irFunction.symbol).irBlockBody { - +irReturn( - irCall(IrSimpleFunctionSymbolImpl(toArrayUtilDescriptor), toArrayType).apply { - putValueArgument( - 0, - IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irFunction.dispatchReceiverParameter!!.symbol) - ) - }) - } - irClass.declarations.add(irFunction) - } else { - //TODO patch visibility - } - - if (nonGenericToArray == null) { - val toArrayDescriptor = SimpleFunctionDescriptorImpl.create( - irClass.descriptor, org.jetbrains.kotlin.descriptors.annotations.Annotations.EMPTY, - toArrayName, CallableMemberDescriptor.Kind.SYNTHESIZED, SourceElement.NO_SOURCE - ) - val createWithDefaultBound = TypeParameterDescriptorImpl.createWithDefaultBound( - toArrayDescriptor, - Annotations.EMPTY, - false, - Variance.INVARIANT, + IrTypeParameterSymbolImpl(typeParameterDescriptor), Name.identifier("T"), - 0 - ) - - val genericArrayType = builtIns.getArrayType(Variance.INVARIANT, createWithDefaultBound.defaultType) - toArrayDescriptor.initialize( - null, - irClass.descriptor.thisAsReceiverParameter, - listOf(createWithDefaultBound), - listOf( - ValueParameterDescriptorImpl( - toArrayDescriptor, - null, - 0, - Annotations.EMPTY, - Name.identifier("array"), - genericArrayType, - false, - false, - false, - null, - SourceElement.NO_SOURCE - ) - ), - genericArrayType, - Modality.OPEN, - Visibilities.PUBLIC - ) - - val toArrayUtilDescriptor = createToArrayUtilDescriptor(builtIns, true) - val toArrayType = toArrayUtilDescriptor.returnType!!.toIrType()!! + index = 0, + variance = Variance.INVARIANT, + isReified = false + ).apply { + typeParameterDescriptor.bind(this) + superTypes.add(irBuiltIns.anyNType) + } + val substitutedArrayType = irBuiltIns.arrayClass.typeWith(typeParameter.defaultType) + val functionDescriptor = WrappedSimpleFunctionDescriptor() val irFunction = IrFunctionImpl( - UNDEFINED_OFFSET, - UNDEFINED_OFFSET, + UNDEFINED_OFFSET, UNDEFINED_OFFSET, JvmLoweredDeclarationOrigin.TO_ARRAY, - toArrayDescriptor, - toArrayType + IrSimpleFunctionSymbolImpl(functionDescriptor), + toArrayName, + Visibilities.PUBLIC, + Modality.OPEN, + returnType = substitutedArrayType, + isInline = false, + isExternal = false, + isTailrec = false, + isSuspend = false + ) + functionDescriptor.bind(irFunction) + irFunction.parent = irClass + + typeParameter.parent = irFunction + irFunction.typeParameters.add(typeParameter) + + + val dispatchReceiverParameterDescriptor = WrappedValueParameterDescriptor() + irFunction.dispatchReceiverParameter = IrValueParameterImpl( + UNDEFINED_OFFSET, UNDEFINED_OFFSET, + JvmLoweredDeclarationOrigin.TO_ARRAY, + IrValueParameterSymbolImpl(dispatchReceiverParameterDescriptor), + Name.special(""), + index = -1, + type = irClass.defaultType, + varargElementType = null, + isCrossinline = false, + isNoinline = false + ).apply { + parent = irFunction + } + val valueParameterDescriptor = WrappedValueParameterDescriptor() + irFunction.valueParameters.add( + IrValueParameterImpl( + UNDEFINED_OFFSET, UNDEFINED_OFFSET, + JvmLoweredDeclarationOrigin.TO_ARRAY, + IrValueParameterSymbolImpl(valueParameterDescriptor), + Name.identifier("array"), + index = 0, + varargElementType = null, + type = substitutedArrayType, + isCrossinline = false, + isNoinline = false + ).apply { + valueParameterDescriptor.bind(this) + parent = irFunction + } ) - irFunction.createParameterDeclarations() irFunction.body = context.createIrBuilder(irFunction.symbol).irBlockBody { +irReturn( - irCall(IrSimpleFunctionSymbolImpl(toArrayUtilDescriptor), toArrayType).apply { + irCall(genericToArrayUtilFunction.symbol, genericToArrayUtilFunction.returnType).apply { putValueArgument( 0, IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irFunction.dispatchReceiverParameter!!.symbol) @@ -178,57 +140,180 @@ private class ToArrayLowering(private val context: JvmBackendContext) : ClassLow } else { //TODO patch visibility } + + if (nonGenericToArray == null) { + val functionDescriptor = WrappedSimpleFunctionDescriptor() + val irFunction = IrFunctionImpl( + UNDEFINED_OFFSET, UNDEFINED_OFFSET, + JvmLoweredDeclarationOrigin.TO_ARRAY, + IrSimpleFunctionSymbolImpl(functionDescriptor), + toArrayName, + Visibilities.PUBLIC, + Modality.OPEN, + returnType = irBuiltIns.arrayClass.typeWith(irBuiltIns.anyType), + isInline = false, + isExternal = false, + isTailrec = false, + isSuspend = false + ) + functionDescriptor.bind(irFunction) + irFunction.parent = irClass + + val dispatchReceiverParameterDescriptor = WrappedValueParameterDescriptor() + irFunction.dispatchReceiverParameter = IrValueParameterImpl( + UNDEFINED_OFFSET, UNDEFINED_OFFSET, + JvmLoweredDeclarationOrigin.TO_ARRAY, + IrValueParameterSymbolImpl(dispatchReceiverParameterDescriptor), + Name.special(""), + index = -1, + type = irClass.defaultType, + varargElementType = null, + isCrossinline = false, + isNoinline = false + ).apply { + parent = irFunction + } + + irFunction.body = context.createIrBuilder(irFunction.symbol).irBlockBody { + +irReturn( + irCall(nonGenericToArrayUtilFunction.symbol, nonGenericToArrayUtilFunction.returnType).apply { + putValueArgument( + 0, + IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irFunction.dispatchReceiverParameter!!.symbol) + ) + }) + } + + irClass.declarations.add(irFunction) + } else { + //TODO patch visibility + } } - private fun createToArrayUtilDescriptor( - builtIns: KotlinBuiltIns, - isGeneric: Boolean - ): SimpleFunctionDescriptorImpl { - val kotlinJvmInternalPackage = KnownPackageFragmentDescriptor(builtIns.builtInsModule, FqName("kotlin.jvm.internal")) + private val kotlinJvmInternalPackageFragment: IrPackageFragment by lazy { + IrExternalPackageFragmentImpl( + IrExternalPackageFragmentSymbolImpl( + EmptyPackageFragmentDescriptor( + context.ir.irModule.descriptor, + FqName("kotlin.jvm.internal") + ) + ) + ) + } - val toArrayUtil = SimpleFunctionDescriptorImpl.create( - KnownClassDescriptor.createClass(Name.identifier("CollectionToArray"), kotlinJvmInternalPackage, listOf(builtIns.anyType)), - Annotations.EMPTY, + private val collectionUtilClass: IrClass by lazy { + val descriptor = WrappedClassDescriptor() + IrClassImpl( + UNDEFINED_OFFSET, UNDEFINED_OFFSET, + JvmLoweredDeclarationOrigin.TO_ARRAY, + IrClassSymbolImpl(descriptor), + Name.identifier("CollectionToArray"), + ClassKind.CLASS, + Visibilities.PUBLIC, + Modality.FINAL, + isCompanion = false, + isInner = false, + isInline = false, + isData = false, + isExternal = false + ).apply { + descriptor.bind(this) + parent = kotlinJvmInternalPackageFragment + superTypes.add(context.irBuiltIns.anyType) + kotlinJvmInternalPackageFragment.declarations.add(this) + } + } + + private fun createToArrayUtilFunction(isGeneric: Boolean): IrSimpleFunction { + val irBuiltIns = context.irBuiltIns + val arrayType = irBuiltIns.arrayClass.typeWith(irBuiltIns.anyNType) + + val utilFunctionDescriptor = WrappedSimpleFunctionDescriptor() + return IrFunctionImpl( + UNDEFINED_OFFSET, UNDEFINED_OFFSET, + JvmLoweredDeclarationOrigin.TO_ARRAY, + IrSimpleFunctionSymbolImpl(utilFunctionDescriptor), Name.identifier("toArray"), - CallableMemberDescriptor.Kind.SYNTHESIZED, - SourceElement.NO_SOURCE - ) - toArrayUtil.initialize( - null, - null, - emptyList(), - listOfNotNull( - ValueParameterDescriptorImpl( - toArrayUtil, - null, - 0, - Annotations.EMPTY, + Visibilities.PUBLIC, + Modality.FINAL, + returnType = arrayType, + isInline = false, + isExternal = false, + isTailrec = false, + isSuspend = false + ).also { irFunction -> + utilFunctionDescriptor.bind(irFunction) + irFunction.parent = collectionUtilClass + + val collectionParameterDescriptor = WrappedValueParameterDescriptor() + irFunction.valueParameters.add( + IrValueParameterImpl( + UNDEFINED_OFFSET, UNDEFINED_OFFSET, + JvmLoweredDeclarationOrigin.TO_ARRAY, + IrValueParameterSymbolImpl(collectionParameterDescriptor), Name.identifier("collection"), - builtIns.collection.defaultType, - false, - false, - false, - null, - SourceElement.NO_SOURCE - ), - if (isGeneric) ValueParameterDescriptorImpl( - toArrayUtil, - null, - 1, - Annotations.EMPTY, - Name.identifier("array"), - builtIns.getArrayType(Variance.INVARIANT, builtIns.anyType), - false, - false, - false, - null, - SourceElement.NO_SOURCE - ) else null - ), - builtIns.array.defaultType, - Modality.OPEN, - Visibilities.PUBLIC - ) - return toArrayUtil + 0, + irBuiltIns.collectionClass.owner.defaultType, + varargElementType = null, + isCrossinline = false, + isNoinline = false + ).apply { + collectionParameterDescriptor.bind(this) + parent = irFunction + } + ) + if (isGeneric) { + val arrayParameterDescriptor = WrappedValueParameterDescriptor() + irFunction.valueParameters.add( + IrValueParameterImpl( + UNDEFINED_OFFSET, UNDEFINED_OFFSET, + JvmLoweredDeclarationOrigin.TO_ARRAY, + IrValueParameterSymbolImpl(arrayParameterDescriptor), + Name.identifier("array"), + 1, + arrayType, + varargElementType = null, + isCrossinline = false, + isNoinline = false + ).apply { + arrayParameterDescriptor.bind(this) + parent = irFunction + } + ) + } + collectionUtilClass.declarations.add(irFunction) + } } -} \ No newline at end of file + + private val nonGenericToArrayUtilFunction: IrSimpleFunction by lazy { createToArrayUtilFunction(false) } + private val genericToArrayUtilFunction: IrSimpleFunction by lazy { createToArrayUtilFunction(true) } + + + private fun IrDeclaration.isGenericToArray(): Boolean { + if (this !is IrSimpleFunction) return false + val signature = context.state.typeMapper.mapAsmMethod(descriptor) + return signature.toString() == "toArray([Ljava/lang/Object;)[Ljava/lang/Object;" + } + + private fun IrDeclaration.isNonGenericToArray(): Boolean { + if (this !is IrSimpleFunction) return false + if (this.name.asString() != "toArray") return false + if (!typeParameters.isEmpty() || !valueParameters.isEmpty()) return false + if (!returnType.isArray()) return false + + return true + } +} + +private fun IrClass.hasSuperClass(pred: (IrClass) -> Boolean): Boolean = + DFS.ifAny( + listOf(this), + { irClass -> irClass.superTypes.mapNotNull { ((it as? IrSimpleType)?.classifier as? IrClassSymbol)?.owner } }, + pred + ) + +// Have to check by name, since irBuiltins is unreliable. +private fun IrClass.isCollectionSubClass() = + hasSuperClass { + it.defaultType.isCollection() + } \ No newline at end of file diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/descriptors/IrBuiltIns.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/descriptors/IrBuiltIns.kt index 5bc98b18ac5..b71a31707d6 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/descriptors/IrBuiltIns.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/descriptors/IrBuiltIns.kt @@ -128,6 +128,8 @@ class IrBuiltIns( val stringType = string.toIrType() val stringClass = builtIns.string.toIrSymbol() + val collectionClass = builtIns.collection.toIrSymbol() + val arrayClass = builtIns.array.toIrSymbol() val throwableType = builtIns.throwable.defaultType.toIrType() diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/irTypePredicates.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/irTypePredicates.kt index 2bb17b46829..cf0d8e90293 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/irTypePredicates.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/irTypePredicates.kt @@ -37,6 +37,7 @@ fun IrType.isNullableAny(): Boolean = isBuiltInClassType(KotlinBuiltIns::isAny, fun IrType.isString(): Boolean = isNotNullClassType(KotlinBuiltIns.FQ_NAMES.string) fun IrType.isNullableString(): Boolean = isNullableClassType(KotlinBuiltIns.FQ_NAMES.string) fun IrType.isArray(): Boolean = isNotNullClassType(KotlinBuiltIns.FQ_NAMES.array) +fun IrType.isCollection(): Boolean = isNotNullClassType(KotlinBuiltIns.FQ_NAMES.collection.toUnsafe()) fun IrType.isNothing(): Boolean = isNotNullClassType(KotlinBuiltIns.FQ_NAMES.nothing) fun IrType.isPrimitiveType(): Boolean = isBuiltInClassType(KotlinBuiltIns::isPrimitiveClass, hasQuestionMark = false)