[IR] Change value classes lowering dispatching strategy

Signed-off-by: Evgeniy.Zhelenskiy <Evgeniy.Zhelenskiy@jetbrains.com>

#KT-1179
This commit is contained in:
Evgeniy.Zhelenskiy
2023-03-29 07:46:05 +02:00
committed by Space Team
parent c1ac580031
commit 2535a87f85
15 changed files with 276 additions and 212 deletions
@@ -52149,6 +52149,12 @@ public class FirLightTreeBlackBoxCodegenTestGenerated extends AbstractFirLightTr
runTest("compiler/testData/codegen/box/valueClasses/mutableSharedMfvcVar.kt");
}
@Test
@TestMetadata("nestedLoweringStart.kt")
public void testNestedLoweringStart() throws Exception {
runTest("compiler/testData/codegen/box/valueClasses/nestedLoweringStart.kt");
}
@Test
@TestMetadata("nothingAsParameterType.kt")
public void testNothingAsParameterType() throws Exception {
@@ -52149,6 +52149,12 @@ public class FirPsiBlackBoxCodegenTestGenerated extends AbstractFirPsiBlackBoxCo
runTest("compiler/testData/codegen/box/valueClasses/mutableSharedMfvcVar.kt");
}
@Test
@TestMetadata("nestedLoweringStart.kt")
public void testNestedLoweringStart() throws Exception {
runTest("compiler/testData/codegen/box/valueClasses/nestedLoweringStart.kt");
}
@Test
@TestMetadata("nothingAsParameterType.kt")
public void testNothingAsParameterType() throws Exception {
@@ -10,7 +10,6 @@ import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.lower.irBlockBody
import org.jetbrains.kotlin.backend.jvm.*
import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
import org.jetbrains.kotlin.backend.jvm.ir.isInlineClassType
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.config.ApiVersion
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
@@ -72,7 +71,6 @@ internal class JvmInlineClassLowering(
override val specificMangle: SpecificMangle
get() = SpecificMangle.Inline
override val IrType.needsHandling get() = isInlineClassType()
override fun visitClassNewDeclarationsWhenParallel(declaration: IrDeclaration) = Unit
override fun visitClassNew(declaration: IrClass): IrClass {
@@ -46,8 +46,6 @@ internal class JvmMultiFieldValueClassLowering(
context: JvmBackendContext,
scopeStack: MutableList<ScopeWithIr>,
) : JvmValueClassAbstractLowering(context, scopeStack) {
override val IrType.needsHandling: Boolean
get() = needsMfvcFlattening()
private sealed class MfvcNodeInstanceAccessor {
abstract val instance: MfvcNodeInstance
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.backend.jvm.lower
import org.jetbrains.kotlin.backend.common.*
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.jvm.*
import org.jetbrains.kotlin.backend.jvm.ir.isValueClassType
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.builders.irReturn
@@ -15,6 +16,8 @@ import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.transformStatement
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.isNothing
import org.jetbrains.kotlin.ir.types.makeNotNull
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.load.java.JvmAbi
@@ -243,68 +246,6 @@ internal abstract class JvmValueClassAbstractLowering(
protected abstract fun createBridgeBody(source: IrSimpleFunction, target: IrSimpleFunction, original: IrFunction, inverted: Boolean)
// Functions for common lowering dispatching
private inner class NeedsToVisit : IrElementVisitor<Boolean, Nothing?> {
override fun visitElement(element: IrElement, data: Nothing?): Boolean = false
override fun visitClass(declaration: IrClass, data: Nothing?): Boolean =
declaration.isSpecificLoweringLogicApplicable() || declaration.declarations.any { it.accept(this, null) }
override fun visitFunction(declaration: IrFunction, data: Nothing?): Boolean =
replacements.quickCheckIfFunctionIsNotApplicable(declaration)
override fun visitFunctionReference(expression: IrFunctionReference, data: Nothing?): Boolean =
visitFunction(expression.symbol.owner, data)
override fun visitFunctionAccess(expression: IrFunctionAccessExpression, data: Nothing?): Boolean =
visitFunction(expression.symbol.owner, data)
override fun visitField(declaration: IrField, data: Nothing?): Boolean = declaration.type.needsHandling
override fun visitFieldAccess(expression: IrFieldAccessExpression, data: Nothing?): Boolean =
visitField(expression.symbol.owner, data)
override fun visitVariable(declaration: IrVariable, data: Nothing?): Boolean = visitValueDeclaration(declaration)
private fun visitValueDeclaration(declaration: IrValueDeclaration) = declaration.type.needsHandling
override fun visitValueParameter(declaration: IrValueParameter, data: Nothing?): Boolean = visitValueDeclaration(declaration)
override fun visitValueAccess(expression: IrValueAccessExpression, data: Nothing?): Boolean =
visitValueDeclaration(expression.symbol.owner)
override fun visitStringConcatenation(expression: IrStringConcatenation, data: Nothing?): Boolean = false
override fun visitReturn(expression: IrReturn, data: Nothing?): Boolean = (expression.returnTargetSymbol.owner as? IrFunction)
?.let { replacements.quickCheckIfFunctionIsNotApplicable(it) } ?: false
override fun visitAnonymousInitializer(declaration: IrAnonymousInitializer, data: Nothing?): Boolean =
(declaration.parent as? IrClass)?.isSpecificLoweringLogicApplicable() == true
private fun visitStatementContainer(container: IrStatementContainer) = container.statements.any { it.accept(this, null) }
override fun visitContainerExpression(expression: IrContainerExpression, data: Nothing?): Boolean =
visitStatementContainer(expression)
override fun visitBlockBody(body: IrBlockBody, data: Nothing?): Boolean = visitStatementContainer(body)
}
internal fun needsToVisitClassNew(declaration: IrClass): Boolean = declaration.accept(NeedsToVisit(), null)
internal fun needsToVisitFunctionReference(expression: IrFunctionReference): Boolean = expression.accept(NeedsToVisit(), null)
internal fun needsToVisitFunctionAccess(expression: IrFunctionAccessExpression): Boolean = expression.accept(NeedsToVisit(), null)
internal fun needsToVisitCall(expression: IrCall): Boolean = expression.accept(NeedsToVisit(), null)
internal fun needsToVisitStringConcatenation(expression: IrStringConcatenation): Boolean = expression.accept(NeedsToVisit(), null)
internal fun needsToVisitGetField(expression: IrGetField): Boolean = expression.accept(NeedsToVisit(), null)
internal fun needsToVisitSetField(expression: IrSetField): Boolean = expression.accept(NeedsToVisit(), null)
internal fun needsToVisitGetValue(expression: IrGetValue): Boolean = expression.accept(NeedsToVisit(), null)
internal fun needsToVisitSetValue(expression: IrSetValue): Boolean = expression.accept(NeedsToVisit(), null)
internal fun needsToVisitVariable(declaration: IrVariable): Boolean = declaration.accept(NeedsToVisit(), null)
internal fun needsToVisitReturn(expression: IrReturn): Boolean = expression.accept(NeedsToVisit(), null)
internal abstract fun visitClassNewDeclarationsWhenParallel(declaration: IrDeclaration)
// forbid other overrides without modifying dispatcher file JvmValueClassLoweringDispatcher.kt
@@ -380,6 +321,4 @@ internal abstract class JvmValueClassAbstractLowering(
final override fun visitErrorExpression(expression: IrErrorExpression) = super.visitErrorExpression(expression)
final override fun visitErrorCallExpression(expression: IrErrorCallExpression) = super.visitErrorCallExpression(expression)
abstract val IrType.needsHandling: Boolean
}
@@ -11,15 +11,21 @@ import org.jetbrains.kotlin.backend.common.ScopeWithIr
import org.jetbrains.kotlin.backend.common.lower.loops.forLoopsPhase
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.MemoizedValueClassLoweringDispatcherSharedData.Access.Body
import org.jetbrains.kotlin.backend.jvm.MemoizedValueClassLoweringDispatcherSharedData.Access.Header
import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.IrAnonymousInitializer
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrVariable
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.transformStatement
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.classifierOrNull
import org.jetbrains.kotlin.ir.types.typeOrNull
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid
val jvmValueClassPhase = makeIrFilePhase(
::JvmValueClassLoweringDispatcher,
@@ -32,7 +38,8 @@ val jvmValueClassPhase = makeIrFilePhase(
prerequisite = setOf(forLoopsPhase, jvmBuiltInsPhase, collectionStubMethodLowering, singleAbstractMethodPhase),
)
internal class JvmValueClassLoweringDispatcher(context: JvmBackendContext) : IrElementTransformerVoidWithContext(), FileLoweringPass {
internal class JvmValueClassLoweringDispatcher(private val context: JvmBackendContext) : IrElementTransformerVoidWithContext(),
FileLoweringPass {
override val scopeStack: MutableList<ScopeWithIr> = mutableListOf()
private val inlineClassLowering: JvmInlineClassLowering = JvmInlineClassLowering(context, scopeStack)
private val multiFieldValueClassLowering: JvmMultiFieldValueClassLowering = JvmMultiFieldValueClassLowering(context, scopeStack)
@@ -42,158 +49,177 @@ internal class JvmValueClassLoweringDispatcher(context: JvmBackendContext) : IrE
irFile.transformChildrenVoid()
}
private fun IrElement.requiresAnyHandling() =
requiresHandling(multiFieldValueClassLowering) || requiresHandling(inlineClassLowering)
override fun visitClassNew(declaration: IrClass): IrClass = if (declaration.requiresAnyHandling()) {
override fun visitClassNew(declaration: IrClass): IrClass = if (declaration.requiresHandling()) {
declaration
.let(multiFieldValueClassLowering::visitClassNew)
.let(inlineClassLowering::visitClassNew)
} else {
declaration.transformChildrenVoid()
for (innerDeclaration in declaration.declarations) {
multiFieldValueClassLowering.visitClassNewDeclarationsWhenParallel(innerDeclaration)
}
for (innerDeclaration in declaration.declarations) {
inlineClassLowering.visitClassNewDeclarationsWhenParallel(innerDeclaration)
}
declaration
}
private fun transformExpressionConsequently(expression: IrExpression) = expression
.transform(multiFieldValueClassLowering, null)
.transform(inlineClassLowering, null)
private fun IrElement.requiresHandling(): Boolean {
val visitor = NeedsToVisit(context)
accept(visitor, null)
return visitor.result
}
}
private fun transformStatementConsequently(statement: IrStatement) = statement
.transformStatement(multiFieldValueClassLowering)
.transformStatement(inlineClassLowering)
private class NeedsToVisit(private val context: JvmBackendContext) : IrElementVisitorVoid {
var result = false
private val replacements = context.valueClassLoweringDispatcherSharedData
private val visitedParameters = mutableSetOf<IrSymbol>()
private fun IrElement.requiresHandling(lowering: JvmValueClassAbstractLowering) =
accept(object : IrElementVisitor<Boolean, Nothing?> {
override fun visitElement(element: IrElement, data: Nothing?): Boolean = false
override fun visitClass(declaration: IrClass, data: Nothing?): Boolean =
lowering.needsToVisitClassNew(declaration) || super.visitClass(declaration, data)
override fun visitElement(element: IrElement) {
if (!result) element.acceptChildrenVoid(this)
}
override fun visitFunctionReference(expression: IrFunctionReference, data: Nothing?): Boolean =
lowering.needsToVisitFunctionReference(expression) || super.visitFunctionReference(expression, data)
private fun IrElement.acceptAndGetResult(): Boolean {
acceptVoid(this@NeedsToVisit)
return result
}
override fun visitFunctionAccess(expression: IrFunctionAccessExpression, data: Nothing?): Boolean =
lowering.needsToVisitFunctionAccess(expression) || super.visitFunctionAccess(expression, data)
private val IrClass.needsHandling: Boolean
get() = isValue || typeParameters.any { it.acceptAndGetResult() }
private val IrType.needsHandling: Boolean
get() = classifierOrNull?.isBound == true && erasedUpperBound.needsHandling || this is IrSimpleType && arguments.any { it.typeOrNull?.needsHandling == true }
override fun visitCall(expression: IrCall, data: Nothing?): Boolean =
lowering.needsToVisitCall(expression) || super.visitCall(expression, data)
override fun visitClass(declaration: IrClass) {
visitClassHeader(declaration)
if (result) return
visitClassBody(declaration)
}
override fun visitStringConcatenation(expression: IrStringConcatenation, data: Nothing?): Boolean =
lowering.needsToVisitStringConcatenation(expression) || super.visitStringConcatenation(expression, data)
private fun visitClassBody(declaration: IrClass) {
if (result) return
result = replacements.classResults.getOrPut(Body to declaration) {
declaration.declarations.any { it.acceptAndGetResult() }
}
}
override fun visitGetField(expression: IrGetField, data: Nothing?): Boolean =
lowering.needsToVisitGetField(expression) || super.visitGetField(expression, data)
private fun visitClassHeader(declaration: IrClass) {
if (result) return
result = replacements.classResults.getOrPut(Header to declaration) {
declaration.needsHandling ||
declaration.typeParameters.any { it.acceptAndGetResult() } ||
declaration.superTypes.mapNotNull { (it.classifierOrNull as? IrClassSymbol)?.owner }.any { visitClassHeader(it); result }
}
}
override fun visitSetField(expression: IrSetField, data: Nothing?): Boolean =
lowering.needsToVisitSetField(expression) || super.visitSetField(expression, data)
override fun visitFunction(declaration: IrFunction) = visitFunction(declaration, withBody = true)
override fun visitGetValue(expression: IrGetValue, data: Nothing?): Boolean =
lowering.needsToVisitGetValue(expression) || super.visitGetValue(expression, data)
private fun visitFunctionHeader(declaration: IrFunction) {
if (result) return
result = replacements.functionResults.getOrPut(Header to declaration) {
declaration.parent.let { it is IrClass && it.needsHandling } ||
declaration.typeParameters.any { it.acceptAndGetResult() } ||
declaration.dispatchReceiverParameter?.acceptAndGetResult() == true ||
declaration.extensionReceiverParameter?.acceptAndGetResult() == true ||
declaration.valueParameters.any { it.acceptAndGetResult() } ||
declaration.returnType.needsHandling ||
(declaration as? IrSimpleFunction)?.overriddenSymbols?.any { visitFunction(it.owner, withBody = false); result } == true
}
}
override fun visitSetValue(expression: IrSetValue, data: Nothing?): Boolean =
lowering.needsToVisitSetValue(expression) || super.visitSetValue(expression, data)
private fun visitFunction(declaration: IrFunction, withBody: Boolean) {
visitFunctionHeader(declaration)
if (result) return
if(withBody) visitFunctionBody(declaration)
}
override fun visitVariable(declaration: IrVariable, data: Nothing?): Boolean =
lowering.needsToVisitVariable(declaration) || super.visitVariable(declaration, data)
private fun visitFunctionBody(declaration: IrFunction) {
if (result) return
result = replacements.functionResults.getOrPut(Body to declaration) {
declaration.body?.acceptAndGetResult() == true
}
}
override fun visitReturn(expression: IrReturn, data: Nothing?): Boolean =
lowering.needsToVisitReturn(expression) || super.visitReturn(expression, data)
override fun visitValueParameter(declaration: IrValueParameter) {
if (result || !visitedParameters.add(declaration.symbol)) return
result = declaration.type.needsHandling
if (result) return
super.visitValueParameter(declaration)
}
override fun visitContainerExpression(expression: IrContainerExpression, data: Nothing?): Boolean =
visitStatementContainer(expression)
override fun visitTypeParameter(declaration: IrTypeParameter) {
if (result || !visitedParameters.add(declaration.symbol)) return
result = declaration.superTypes.any { it.needsHandling }
if (result) return
super.visitTypeParameter(declaration)
}
override fun visitBlockBody(body: IrBlockBody, data: Nothing?): Boolean =
visitStatementContainer(body)
private fun visitStatementContainer(expression: IrStatementContainer) = expression.statements.any { it.accept(this, null) }
}, null)
override fun visitFunctionReference(expression: IrFunctionReference): IrExpression = if (expression.requiresAnyHandling()) {
transformExpressionConsequently(expression)
} else {
override fun visitFunctionReference(expression: IrFunctionReference) {
if (result) return
visitFunction(expression.symbol.owner, withBody = false)
if (result) return
super.visitFunctionReference(expression)
}
override fun visitFunctionAccess(expression: IrFunctionAccessExpression): IrExpression = if (expression.requiresAnyHandling()) {
transformExpressionConsequently(expression)
} else {
override fun visitFunctionAccess(expression: IrFunctionAccessExpression) {
if (result) return
visitFunction(expression.symbol.owner, withBody = false)
if (result) return
super.visitFunctionAccess(expression)
}
override fun visitCall(expression: IrCall): IrExpression = if (expression.requiresAnyHandling()) {
transformExpressionConsequently(expression)
} else {
super.visitCall(expression)
override fun visitField(declaration: IrField) = visitField(declaration, withBody = true)
private fun visitFieldHeader(declaration: IrField) {
if (result) return
result = replacements.fieldResults.getOrPut(Header to declaration) {
declaration.type.needsHandling
}
}
override fun visitStringConcatenation(expression: IrStringConcatenation): IrExpression = if (expression.requiresAnyHandling()) {
transformExpressionConsequently(expression)
} else {
super.visitStringConcatenation(expression)
private fun visitFieldBody(declaration: IrField) {
if (result) return
result = replacements.fieldResults.getOrPut(Body to declaration) {
super.visitField(declaration)
result
}
}
override fun visitGetField(expression: IrGetField): IrExpression = if (expression.requiresAnyHandling()) {
transformExpressionConsequently(expression)
} else {
super.visitGetField(expression)
private fun visitField(declaration: IrField, withBody: Boolean) {
visitFieldHeader(declaration)
if (withBody) visitFieldBody(declaration)
}
override fun visitSetField(expression: IrSetField): IrExpression = if (expression.requiresAnyHandling()) {
transformExpressionConsequently(expression)
} else {
super.visitSetField(expression)
override fun visitFieldAccess(expression: IrFieldAccessExpression) {
if (result) return
visitField(expression.symbol.owner, withBody = false)
if (result) return
super.visitFieldAccess(expression)
}
override fun visitGetValue(expression: IrGetValue): IrExpression = if (expression.requiresAnyHandling()) {
transformExpressionConsequently(expression)
} else {
super.visitGetValue(expression)
}
override fun visitSetValue(expression: IrSetValue): IrExpression = if (expression.requiresAnyHandling()) {
transformExpressionConsequently(expression)
} else {
super.visitSetValue(expression)
}
override fun visitVariable(declaration: IrVariable): IrStatement = if (declaration.requiresAnyHandling()) {
transformStatementConsequently(declaration)
} else {
override fun visitVariable(declaration: IrVariable) {
if (result) return
result = declaration.type.needsHandling
if (result) return
super.visitVariable(declaration)
}
override fun visitReturn(expression: IrReturn): IrExpression = if (expression.requiresAnyHandling()) {
transformExpressionConsequently(expression)
} else {
super.visitReturn(expression)
override fun visitStringConcatenation(expression: IrStringConcatenation) {
if (result) return
result = expression.arguments.any { it.type.needsHandling }
if (result) return
super.visitStringConcatenation(expression)
}
override fun visitAnonymousInitializerNew(declaration: IrAnonymousInitializer): IrStatement = if (declaration.requiresAnyHandling()) {
transformStatementConsequently(declaration)
} else {
super.visitAnonymousInitializerNew(declaration)
override fun visitCall(expression: IrCall) {
if (result) return
if (expression.symbol == context.irBuiltIns.eqeqSymbol) {
for (it in 0 until expression.valueArgumentsCount) {
result = expression.getValueArgument(it)?.type?.needsHandling ?: false
if (result) return
}
}
super.visitCall(expression)
}
private fun visitStatementContainer(container: IrStatementContainer) = if (container.statements.any { it.requiresAnyHandling() }) {
multiFieldValueClassLowering.visitStatementContainer(container)
inlineClassLowering.visitStatementContainer(container)
} else {
container.statements.replaceAll { it.transformStatement(this) }
override fun visitExpression(expression: IrExpression) {
if (result) return
result = expression.type.needsHandling
if (result) return
super.visitExpression(expression)
}
override fun visitContainerExpression(expression: IrContainerExpression): IrExpression {
visitStatementContainer(expression)
return expression
}
override fun visitBlockBody(body: IrBlockBody): IrBody {
visitStatementContainer(body)
return body
}
}
}
@@ -167,8 +167,9 @@ class JvmBackendContext(
val inlineClassReplacements = MemoizedInlineClassReplacements(state.functionsWithInlineClassReturnTypesMangled, irFactory, this)
val multiFieldValueClassReplacements =
MemoizedMultiFieldValueClassReplacements(irFactory, this)
val multiFieldValueClassReplacements = MemoizedMultiFieldValueClassReplacements(irFactory, this)
val valueClassLoweringDispatcherSharedData = MemoizedValueClassLoweringDispatcherSharedData()
val continuationClassesVarsCountByType: MutableMap<IrAttributeContainer, Map<Type, Int>> = hashMapOf()
@@ -13,8 +13,11 @@ import org.jetbrains.kotlin.ir.IrBuiltIns
import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
import org.jetbrains.kotlin.ir.types.impl.IrStarProjectionImpl
import org.jetbrains.kotlin.ir.types.isNothing
import org.jetbrains.kotlin.ir.types.makeNotNull
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.InlineClassDescriptorResolver
@@ -83,13 +86,6 @@ class MemoizedInlineClassReplacements(
}
}
override fun quickCheckIfFunctionIsNotApplicable(function: IrFunction) = !(
function.parent.let { (it is IrClass && it.isSingleFieldValueClass) } ||
function.dispatchReceiverParameter?.type?.isInlineClassType() == true ||
function.extensionReceiverParameter?.type?.isInlineClassType() == true ||
function.valueParameters.any { it.type.isInlineClassType() } || function.returnType.isInlineClassType()
)
/**
* Get the box function for an inline class. Concretely, this is a synthetic
* static function named "box-impl" which takes an unboxed value and returns
@@ -22,10 +22,7 @@ import org.jetbrains.kotlin.ir.expressions.IrComposite
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrStatementOriginImpl
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.defaultType
import org.jetbrains.kotlin.ir.types.isNothing
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.InlineClassDescriptorResolver
@@ -290,13 +287,6 @@ class MemoizedMultiFieldValueClassReplacements(
}
}
override fun quickCheckIfFunctionIsNotApplicable(function: IrFunction): Boolean = !(
function.parent.let { it is IrClass && it.isMultiFieldValueClass } ||
function.dispatchReceiverParameter?.type?.needsMfvcFlattening() == true ||
function.extensionReceiverParameter?.type?.needsMfvcFlattening() == true ||
function.valueParameters.any { it.type.needsMfvcFlattening() }
)
private val getReplacementForRegularClassConstructorImpl: (IrConstructor) -> IrConstructor? =
storageManager.createMemoizedFunctionWithNullableValues { constructor ->
when {
@@ -29,8 +29,7 @@ abstract class MemoizedValueClassAbstractReplacements(
/**
* Get a replacement for a function or a constructor.
*/
fun getReplacementFunction(function: IrFunction) =
if (quickCheckIfFunctionIsNotApplicable(function)) null else getReplacementFunctionImpl(function)
fun getReplacementFunction(function: IrFunction) = getReplacementFunctionImpl(function)
protected abstract val getReplacementFunctionImpl: (IrFunction) -> IrSimpleFunction?
@@ -138,6 +137,4 @@ abstract class MemoizedValueClassAbstractReplacements(
getReplacementFunction(function) ?: function.also {
function.overriddenSymbols = replaceOverriddenSymbols(function)
}
abstract fun quickCheckIfFunctionIsNotApplicable(function: IrFunction): Boolean
}
@@ -0,0 +1,20 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrField
import org.jetbrains.kotlin.ir.declarations.IrFunction
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.ConcurrentMap
class MemoizedValueClassLoweringDispatcherSharedData {
enum class Access { Header, Body }
val functionResults: ConcurrentMap<Pair<Access, IrFunction>, Boolean> = ConcurrentHashMap()
val classResults: ConcurrentMap<Pair<Access, IrClass>, Boolean> = ConcurrentHashMap()
val fieldResults: ConcurrentMap<Pair<Access, IrField>, Boolean> = ConcurrentHashMap()
}
@@ -0,0 +1,35 @@
// WITH_STDLIB
// TARGET_BACKEND: JVM_IR
// LANGUAGE: +ValueClasses
// CHECK_BYTECODE_LISTING
// FIR_IDENTICAL
@JvmInline
value class Point(val x: Double, val y: Double)
class A {
fun b(p: Point) {
res = p
}
}
var res: Any? = null
fun toA(out: A): A {
fun g(p: List<Point>) {
out.b(p.first())
}
g(listOf(Point(1.0, 2.0)))
return out
}
fun box(): String {
val a = A()
toA(a)
require(res.toString() == Point(1.0, 2.0).toString())
return "OK"
}
@@ -0,0 +1,40 @@
@kotlin.Metadata
public final class A {
// source: 'nestedLoweringStart.kt'
public method <init>(): void
public final method b-1Nq-99U(p0: double, p1: double): void
}
@kotlin.Metadata
public final class NestedLoweringStartKt {
// source: 'nestedLoweringStart.kt'
private static @org.jetbrains.annotations.Nullable field res: java.lang.Object
static method <clinit>(): void
public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String
public final static @org.jetbrains.annotations.Nullable method getRes(): java.lang.Object
public final static method setRes(@org.jetbrains.annotations.Nullable p0: java.lang.Object): void
private final static method toA$g(p0: A, p1: java.util.List): void
public final static @org.jetbrains.annotations.NotNull method toA(@org.jetbrains.annotations.NotNull p0: A): A
}
@kotlin.jvm.JvmInline
@kotlin.Metadata
public final class Point {
// source: 'nestedLoweringStart.kt'
private final field x: double
private final field y: double
private synthetic method <init>(p0: double, p1: double): void
public synthetic final static method box-impl(p0: double, p1: double): Point
public final static method constructor-impl(p0: double, p1: double): void
public method equals(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean
public static method equals-impl(p0: double, p1: double, p2: java.lang.Object): boolean
public final static method equals-impl0(p0: double, p1: double, p2: double, p3: double): boolean
public final method getX(): double
public final method getY(): double
public method hashCode(): int
public static method hashCode-impl(p0: double, p1: double): int
public @org.jetbrains.annotations.NotNull method toString(): java.lang.String
public static method toString-impl(p0: double, p1: double): java.lang.String
public synthetic final method unbox-impl-x(): double
public synthetic final method unbox-impl-y(): double
}
@@ -52149,6 +52149,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/valueClasses/mutableSharedMfvcVar.kt");
}
@Test
@TestMetadata("nestedLoweringStart.kt")
public void testNestedLoweringStart() throws Exception {
runTest("compiler/testData/codegen/box/valueClasses/nestedLoweringStart.kt");
}
@Test
@TestMetadata("nothingAsParameterType.kt")
public void testNothingAsParameterType() throws Exception {
@@ -52149,6 +52149,12 @@ public class IrBlackBoxCodegenWithIrInlinerTestGenerated extends AbstractIrBlack
runTest("compiler/testData/codegen/box/valueClasses/mutableSharedMfvcVar.kt");
}
@Test
@TestMetadata("nestedLoweringStart.kt")
public void testNestedLoweringStart() throws Exception {
runTest("compiler/testData/codegen/box/valueClasses/nestedLoweringStart.kt");
}
@Test
@TestMetadata("nothingAsParameterType.kt")
public void testNothingAsParameterType() throws Exception {