JVM_IR: generate default constructor

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."
This commit is contained in:
Ting-Yuan Huang
2019-05-24 23:54:57 -07:00
committed by max-kammerer
parent 440f327e74
commit 74e8c7c1c5
10 changed files with 54 additions and 8 deletions
@@ -114,6 +114,7 @@ val jvmPhases = namedIrFilePhase<JvmBackendContext>(
annotationPhase then
tailrecPhase then
jvmDefaultConstructorPhase then
defaultArgumentStubPhase then
interfacePhase then
@@ -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)
}
}
}
}
}
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM
// WITH_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM
// WITH_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM
// WITH_RUNTIME
@@ -1,5 +1,4 @@
// !LANGUAGE: +MultiPlatformProjects
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM
// WITH_RUNTIME
// FILE: common.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.*
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM
// FILE: WithPrimary.java
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
package test
class A(val a: Int = 1)
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
package test
class A(val a: Int = 1, val b: String = "default")