diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt index 2adb559c666..dadafffc4d1 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt @@ -114,6 +114,7 @@ val jvmPhases = namedIrFilePhase( annotationPhase then tailrecPhase then + jvmDefaultConstructorPhase then defaultArgumentStubPhase then interfacePhase then diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmDefaultConstructorLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmDefaultConstructorLowering.kt new file mode 100644 index 00000000000..985d78b784a --- /dev/null +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmDefaultConstructorLowering.kt @@ -0,0 +1,53 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. 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.lower + +import org.jetbrains.kotlin.backend.common.ClassLoweringPass +import org.jetbrains.kotlin.backend.common.ir.passTypeArgumentsFrom +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.ir.builders.declarations.addConstructor +import org.jetbrains.kotlin.ir.builders.irBlockBody +import org.jetbrains.kotlin.ir.builders.irDelegatingConstructorCall +import org.jetbrains.kotlin.ir.declarations.IrClass +import org.jetbrains.kotlin.ir.util.constructors +import org.jetbrains.kotlin.ir.util.hasDefaultValue + +internal val jvmDefaultConstructorPhase = makeIrFilePhase( + ::JvmDefaultConstructorLowering, + name = "JvmDefaultConstructor", + description = "Generate default constructors for Java" +) + +// Quoted from https://kotlinlang.org/docs/reference/classes.html +// +// "On the JVM, if all of the parameters of the primary constructor have default values, the compiler will generate an additional +// parameterless constructor which will use the default values. This makes it easier to use Kotlin with libraries such as Jackson +// or JPA that create class instances through parameterless constructors." +private class JvmDefaultConstructorLowering(val context: JvmBackendContext) : ClassLoweringPass { + + override fun lower(irClass: IrClass) { + val primaryConstructor = irClass.constructors.firstOrNull { it.isPrimary } ?: return + + if (!primaryConstructor.valueParameters.all { it.hasDefaultValue() }) + return + + // Skip if the default constructor is already defined by user. + if (irClass.constructors.any { it.valueParameters.isEmpty() }) + return + + irClass.addConstructor().apply { + val irBuilder = context.createIrBuilder(this.symbol, startOffset, endOffset) + body = irBuilder.irBlockBody { + +irDelegatingConstructorCall(primaryConstructor).apply { + passTypeArgumentsFrom(irClass) + passTypeArgumentsFrom(primaryConstructor, irClass.typeParameters.size) + } + } + } + } +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/defaultArguments/constructor/checkIfConstructorIsSynthetic.kt b/compiler/testData/codegen/box/defaultArguments/constructor/checkIfConstructorIsSynthetic.kt index 806646735fc..562c46fb3fe 100644 --- a/compiler/testData/codegen/box/defaultArguments/constructor/checkIfConstructorIsSynthetic.kt +++ b/compiler/testData/codegen/box/defaultArguments/constructor/checkIfConstructorIsSynthetic.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // TARGET_BACKEND: JVM // WITH_RUNTIME diff --git a/compiler/testData/codegen/box/defaultArguments/constructor/manyArgs.kt b/compiler/testData/codegen/box/defaultArguments/constructor/manyArgs.kt index 6f861a15f21..9591a15c803 100644 --- a/compiler/testData/codegen/box/defaultArguments/constructor/manyArgs.kt +++ b/compiler/testData/codegen/box/defaultArguments/constructor/manyArgs.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // TARGET_BACKEND: JVM // WITH_RUNTIME diff --git a/compiler/testData/codegen/box/jvmOverloads/privateClass.kt b/compiler/testData/codegen/box/jvmOverloads/privateClass.kt index a7fb95f05c2..772a5ea10e6 100644 --- a/compiler/testData/codegen/box/jvmOverloads/privateClass.kt +++ b/compiler/testData/codegen/box/jvmOverloads/privateClass.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // TARGET_BACKEND: JVM // WITH_RUNTIME diff --git a/compiler/testData/codegen/box/multiplatform/noArgActualConstructor.kt b/compiler/testData/codegen/box/multiplatform/noArgActualConstructor.kt index 4689a10d638..959210610ab 100644 --- a/compiler/testData/codegen/box/multiplatform/noArgActualConstructor.kt +++ b/compiler/testData/codegen/box/multiplatform/noArgActualConstructor.kt @@ -1,5 +1,4 @@ // !LANGUAGE: +MultiPlatformProjects -// IGNORE_BACKEND: JVM_IR // TARGET_BACKEND: JVM // WITH_RUNTIME // FILE: common.kt diff --git a/compiler/testData/codegen/box/platformTypes/primitives/equalsNull_withExplicitFlag.kt b/compiler/testData/codegen/box/platformTypes/primitives/equalsNull_withExplicitFlag.kt index 5fefcdab981..f88168f008e 100644 --- a/compiler/testData/codegen/box/platformTypes/primitives/equalsNull_withExplicitFlag.kt +++ b/compiler/testData/codegen/box/platformTypes/primitives/equalsNull_withExplicitFlag.kt @@ -1,5 +1,4 @@ // KOTLIN_CONFIGURATION_FLAGS: +JVM.NO_EXCEPTION_ON_EXPLICIT_EQUALS_FOR_BOXED_NULL -// TARGET_BACKEND: JVM // WITH_RUNTIME // FILE: test.kt import kotlin.test.* diff --git a/compiler/testData/codegen/box/secondaryConstructors/withPrimary.kt b/compiler/testData/codegen/box/secondaryConstructors/withPrimary.kt index c3b419f5b56..28080ec08d1 100644 --- a/compiler/testData/codegen/box/secondaryConstructors/withPrimary.kt +++ b/compiler/testData/codegen/box/secondaryConstructors/withPrimary.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // TARGET_BACKEND: JVM // FILE: WithPrimary.java diff --git a/compiler/testData/compileJavaAgainstKotlin/class/DefaultConstructor.kt b/compiler/testData/compileJavaAgainstKotlin/class/DefaultConstructor.kt index 1a80403528c..84f7685ab88 100644 --- a/compiler/testData/compileJavaAgainstKotlin/class/DefaultConstructor.kt +++ b/compiler/testData/compileJavaAgainstKotlin/class/DefaultConstructor.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR package test class A(val a: Int = 1) diff --git a/compiler/testData/compileJavaAgainstKotlin/class/DefaultConstructorWithTwoArgs.kt b/compiler/testData/compileJavaAgainstKotlin/class/DefaultConstructorWithTwoArgs.kt index 10dd7c7c617..e0cb4b06bf3 100644 --- a/compiler/testData/compileJavaAgainstKotlin/class/DefaultConstructorWithTwoArgs.kt +++ b/compiler/testData/compileJavaAgainstKotlin/class/DefaultConstructorWithTwoArgs.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR package test class A(val a: Int = 1, val b: String = "default")