diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/ArrayConstructorLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/ArrayConstructorLowering.kt index 9905cc2731b..094d8e8b910 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/ArrayConstructorLowering.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/ArrayConstructorLowering.kt @@ -9,20 +9,27 @@ import org.jetbrains.kotlin.backend.common.BodyLoweringPass import org.jetbrains.kotlin.backend.common.CommonBackendContext import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext import org.jetbrains.kotlin.backend.common.ir.asInlinable +import org.jetbrains.kotlin.backend.common.ir.copyValueParametersFrom import org.jetbrains.kotlin.backend.common.ir.inline +import org.jetbrains.kotlin.descriptors.DescriptorVisibilities import org.jetbrains.kotlin.ir.builders.* -import org.jetbrains.kotlin.ir.declarations.IrConstructor -import org.jetbrains.kotlin.ir.declarations.IrDeclaration -import org.jetbrains.kotlin.ir.declarations.IrSymbolOwner -import org.jetbrains.kotlin.ir.expressions.IrBody -import org.jetbrains.kotlin.ir.expressions.IrConstructorCall -import org.jetbrains.kotlin.ir.expressions.IrExpression -import org.jetbrains.kotlin.ir.expressions.copyTypeArgumentsFrom +import org.jetbrains.kotlin.ir.builders.declarations.buildFun +import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.expressions.* +import org.jetbrains.kotlin.ir.expressions.impl.IrCompositeImpl +import org.jetbrains.kotlin.ir.expressions.impl.IrFunctionReferenceImpl import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol +import org.jetbrains.kotlin.ir.types.IrSimpleType +import org.jetbrains.kotlin.ir.types.IrTypeProjection import org.jetbrains.kotlin.ir.types.classifierOrFail import org.jetbrains.kotlin.ir.types.getClass -import org.jetbrains.kotlin.ir.util.* +import org.jetbrains.kotlin.ir.util.constructedClass +import org.jetbrains.kotlin.ir.util.constructors +import org.jetbrains.kotlin.ir.util.functions +import org.jetbrains.kotlin.ir.util.patchDeclarationParents +import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid +import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.util.OperatorNameConventions class ArrayConstructorLowering(val context: CommonBackendContext) : BodyLoweringPass { @@ -37,18 +44,20 @@ private class ArrayConstructorTransformer( ) : IrElementTransformerVoidWithContext() { // Array(size, init) -> Array(size) - private fun arrayInlineToSizeConstructor(irConstructor: IrConstructor): IrFunctionSymbol? { - val clazz = irConstructor.constructedClass.symbol - return when { - irConstructor.valueParameters.size != 2 -> null - clazz == context.irBuiltIns.arrayClass -> context.ir.symbols.arrayOfNulls // Array has no unary constructor: it can only exist for Array - context.irBuiltIns.primitiveArrays.contains(clazz) -> clazz.constructors.single { it.owner.valueParameters.size == 1 } - else -> null + companion object { + internal fun arrayInlineToSizeConstructor(context: CommonBackendContext, irConstructor: IrConstructor): IrFunctionSymbol? { + val clazz = irConstructor.constructedClass.symbol + return when { + irConstructor.valueParameters.size != 2 -> null + clazz == context.irBuiltIns.arrayClass -> context.ir.symbols.arrayOfNulls // Array has no unary constructor: it can only exist for Array + context.irBuiltIns.primitiveArrays.contains(clazz) -> clazz.constructors.single { it.owner.valueParameters.size == 1 } + else -> null + } } } override fun visitConstructorCall(expression: IrConstructorCall): IrExpression { - val sizeConstructor = arrayInlineToSizeConstructor(expression.symbol.owner) + val sizeConstructor = arrayInlineToSizeConstructor(context, expression.symbol.owner) ?: return super.visitConstructorCall(expression) // inline fun Array(size: Int, invokable: (Int) -> T): Array { // val result = arrayOfNulls(size) @@ -90,3 +99,80 @@ private class ArrayConstructorTransformer( } } } + + +object arrayConstuctorWrapper : IrDeclarationOriginImpl("arrayConstuctorWrapper") {} + +class ArrayConstructorReferenceLowering(val context: CommonBackendContext) : BodyLoweringPass { + override fun lower(irBody: IrBody, container: IrDeclaration) { + irBody.transformChildrenVoid(ArrayConstructorReferenceTransformer(context, container as IrSymbolOwner)) + } + + private class ArrayConstructorReferenceTransformer(val context: CommonBackendContext, val container: IrSymbolOwner) : IrElementTransformerVoid() { + override fun visitFunctionReference(expression: IrFunctionReference): IrExpression { + expression.transformChildrenVoid() + val target = expression.symbol.owner + + if (target !is IrConstructor) return expression + + if (ArrayConstructorTransformer.arrayInlineToSizeConstructor(context, target) == null) return expression + + return expression.run { + IrCompositeImpl(startOffset, endOffset, type, origin).apply { + val wrapper = createFunctionReferenceWrapper(expression, target) + statements.add(wrapper) + statements.add( + IrFunctionReferenceImpl( + startOffset, + endOffset, + type, + wrapper.symbol, + 0, + valueArgumentsCount, + target.symbol, + origin + ) + ) + } + } + } + + private fun createFunctionReferenceWrapper(expression: IrFunctionReference, target: IrConstructor): IrSimpleFunction { + val typeArguments = with(expression.type as IrSimpleType) { arguments } + assert(typeArguments.size == 3) + val arrayType = (typeArguments[2] as IrTypeProjection).type + val arrayElementType = ((arrayType as IrSimpleType).arguments.singleOrNull() as? IrTypeProjection)?.type + + val wrapper = context.irFactory.buildFun { + startOffset = expression.startOffset + endOffset = expression.endOffset + origin = arrayConstuctorWrapper + name = Name.special("") + visibility = DescriptorVisibilities.LOCAL + + } + + val substitutionMap = target.typeParameters.singleOrNull()?.let { mapOf(it.symbol to arrayElementType!!) } ?: emptyMap() + wrapper.copyValueParametersFrom(target, substitutionMap) + + wrapper.returnType = arrayType + wrapper.parent = container as IrDeclarationParent + wrapper.body = context.irFactory.createBlockBody(expression.startOffset, expression.endOffset).also { body -> + with(context.createIrBuilder(wrapper.symbol)) { + body.statements.add(irReturn( + irCall(target.symbol, arrayType).also { call -> + if (call.typeArgumentsCount != 0) { + assert(call.typeArgumentsCount == 1) + call.putTypeArgument(0, arrayElementType) + } + call.putValueArgument(0, irGet(wrapper.valueParameters[0])) + call.putValueArgument(1, irGet(wrapper.valueParameters[1])) + } + )) + } + } + + return wrapper + } + } +} \ No newline at end of file diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt index 3e0854fa1ba..f0c30bdb8e6 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt @@ -21,8 +21,8 @@ import org.jetbrains.kotlin.ir.backend.js.lower.calls.CallsLowering import org.jetbrains.kotlin.ir.backend.js.lower.cleanup.CleanupLowering import org.jetbrains.kotlin.ir.backend.js.lower.coroutines.JsSuspendFunctionsLowering import org.jetbrains.kotlin.ir.backend.js.lower.inline.CopyInlineFunctionBodyLowering -import org.jetbrains.kotlin.ir.backend.js.lower.inline.jsRecordExtractedLocalClasses import org.jetbrains.kotlin.ir.backend.js.lower.inline.RemoveInlineDeclarationsWithReifiedTypeParametersLowering +import org.jetbrains.kotlin.ir.backend.js.lower.inline.jsRecordExtractedLocalClasses import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrModuleFragment @@ -192,10 +192,17 @@ private val jsCodeOutliningPhase = makeBodyLoweringPhase( description = "Outline js() calls where JS code references Kotlin locals" ) +private val arrayConstructorReferencePhase = makeBodyLoweringPhase( + ::ArrayConstructorReferenceLowering, + name = "ArrayConstructorReference", + description = "Transform `::Array` into a lambda" +) + private val arrayConstructorPhase = makeBodyLoweringPhase( ::ArrayConstructorLowering, name = "ArrayConstructor", - description = "Transform `Array(size) { index -> value }` into a loop" + description = "Transform `Array(size) { index -> value }` into a loop", + prerequisite = setOf(arrayConstructorReferencePhase) ) private val sharedVariablesLoweringPhase = makeBodyLoweringPhase( @@ -721,6 +728,7 @@ private val loweringList = listOf( expectDeclarationsRemovingPhase, stripTypeAliasDeclarationsPhase, jsCodeOutliningPhase, + arrayConstructorReferencePhase, arrayConstructorPhase, lateinitNullableFieldsPhase, lateinitDeclarationLoweringPhase,