Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,16 @@ import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.backend.jvm.JvmLoweredStatementOrigin
import org.jetbrains.kotlin.backend.jvm.ir.getJvmVisibilityOfDefaultArgumentStub
import org.jetbrains.kotlin.backend.jvm.ir.isBoxedInlineClassType
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.util.hasAnnotation
import org.jetbrains.kotlin.ir.util.isFinalClass
import org.jetbrains.kotlin.ir.util.isTopLevelDeclaration
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.JvmStandardClassIds

@PhasePrerequisites(
Expand All @@ -32,7 +37,26 @@ internal class JvmDefaultArgumentStubGenerator(context: JvmBackendContext) : Def
) {
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
if (declaration is IrFunction && declaration.hasAnnotation(JvmStandardClassIds.JVM_EXPOSE_BOXED_ANNOTATION_FQ_NAME)) return null
return super.transformFlat(declaration)
val lowered = super.transformFlat(declaration) ?: return null
if (lowered.size != 2) return lowered
val stub = lowered[1] as? IrFunction ?: return lowered
// KT-78051: For value class parameters with nullable underlying types,
// the $default stub parameter stays boxed while the implementation
// parameter is unboxed. IrInlineDefaultCodegen copies bytecode verbatim,
// causing VerifyError due to the type mismatch.
if (stub.parameters.none { it.type.isBoxedInlineClassType() }) return lowered

stub.body?.transformChildrenVoid(object : IrElementTransformerVoid() {
override fun visitCall(expression: IrCall): IrExpression {
if (expression.origin == JvmLoweredStatementOrigin.DEFAULT_STUB_CALL_TO_IMPLEMENTATION) {
// Clearing the origin forces IrInlineCodegen which handles type coercion.
expression.origin = null
}
return super.visitCall(expression)
}
})

return lowered
}

override fun defaultArgumentStubVisibility(function: IrFunction) = function.getJvmVisibilityOfDefaultArgumentStub()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// WITH_STDLIB
// TARGET_BACKEND: JVM_IR

@JvmInline
value class ICNullableString(val s: String?)

@JvmInline
value class ICNullableInt(val x: Int?)

@JvmInline
value class ICString(val s: String)

@JvmInline
value class ICInt(val x: Int)

fun fooNullableString(ic: ICNullableString) {
if (ic.s != "OK") throw AssertionError("Fail NullableString: ${ic.s}")
}

fun fooNullableInt(ic: ICNullableInt) {
if (ic.x != 42) throw AssertionError("Fail NullableInt: ${ic.x}")
}

fun fooString(ic: ICString) {
if (ic.s != "OK") throw AssertionError("Fail String: ${ic.s}")
}

fun fooInt(ic: ICInt) {
if (ic.x != 42) throw AssertionError("Fail Int: ${ic.x}")
}

inline fun withDefaultICNullableString(ic: ICNullableString = ICNullableString("OK")) {
fooNullableString(ic)
}

inline fun withDefaultICNullableInt(ic: ICNullableInt = ICNullableInt(42)) {
fooNullableInt(ic)
}

inline fun withDefaultICString(ic: ICString = ICString("OK")) {
fooString(ic)
}

inline fun withDefaultICInt(ic: ICInt = ICInt(42)) {
fooInt(ic)
}

// From the original bug report
inline fun withDefaultICAndCrossinline(
ic: ICNullableString = ICNullableString("OK"),
crossinline check: (ICNullableString) -> Unit
) {
check(ic)
}

fun box(): String {
withDefaultICNullableString()
withDefaultICNullableInt()
withDefaultICString()
withDefaultICInt()

withDefaultICAndCrossinline { ic ->
if (ic.s != "OK") throw AssertionError("Fail crossinline: ${ic.s}")
}

return "OK"
}