[IR] Support default arguments
Signed-off-by: Evgeniy.Zhelenskiy <Evgeniy.Zhelenskiy@jetbrains.com> #KT-1179
This commit is contained in:
committed by
Space Team
parent
0c70b60988
commit
51e76aa19a
+6
@@ -50441,6 +50441,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
|||||||
runTest("compiler/testData/codegen/box/valueClasses/conditionalExpressions.kt", TransformersFunctions.getReplaceOptionalJvmInlineAnnotationWithReal());
|
runTest("compiler/testData/codegen/box/valueClasses/conditionalExpressions.kt", TransformersFunctions.getReplaceOptionalJvmInlineAnnotationWithReal());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("defaultParameters.kt")
|
||||||
|
public void testDefaultParameters() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/valueClasses/defaultParameters.kt", TransformersFunctions.getReplaceOptionalJvmInlineAnnotationWithReal());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("equality.kt")
|
@TestMetadata("equality.kt")
|
||||||
public void testEquality() throws Exception {
|
public void testEquality() throws Exception {
|
||||||
|
|||||||
+64
-23
@@ -606,18 +606,50 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
|||||||
.zipWithNext { start: Int, finish: Int -> replacement.explicitParameters.slice(start until finish) }
|
.zipWithNext { start: Int, finish: Int -> replacement.explicitParameters.slice(start until finish) }
|
||||||
)
|
)
|
||||||
for (i in old2newList.indices) {
|
for (i in old2newList.indices) {
|
||||||
val (param, newParamList) = old2newList[i]
|
val (oldParameter, newParamList) = old2newList[i]
|
||||||
when (val structure = parametersStructure[i]) {
|
when (val structure = parametersStructure[i]) {
|
||||||
|
is RegularMapping -> valueDeclarationsRemapper.registerReplacement(oldParameter, newParamList.single())
|
||||||
is MultiFieldValueClassMapping -> {
|
is MultiFieldValueClassMapping -> {
|
||||||
val mfvcNodeInstance = structure.rootMfvcNode.createInstanceFromValueDeclarationsAndBoxType(
|
val mfvcNodeInstance = structure.rootMfvcNode.createInstanceFromValueDeclarationsAndBoxType(
|
||||||
structure.boxedType, newParamList
|
structure.boxedType, newParamList
|
||||||
)
|
)
|
||||||
valueDeclarationsRemapper.registerReplacement(param, mfvcNodeInstance)
|
valueDeclarationsRemapper.registerReplacement(oldParameter, mfvcNodeInstance)
|
||||||
}
|
}
|
||||||
|
|
||||||
is RegularMapping -> valueDeclarationsRemapper.registerReplacement(param, newParamList.single())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
withinScope(replacement) {
|
||||||
|
addDefaultArgumentsIfNeeded(replacement, old2newList, parametersStructure)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addDefaultArgumentsIfNeeded(
|
||||||
|
replacement: IrFunction,
|
||||||
|
old2newList: List<Pair<IrValueParameter, List<IrValueParameter>>>,
|
||||||
|
parametersStructure: List<RemappedParameter>
|
||||||
|
) {
|
||||||
|
for (i in old2newList.indices) {
|
||||||
|
val (param, newParamList) = old2newList[i]
|
||||||
|
val defaultValue = replacements.oldMfvcDefaultArguments[param] ?: continue
|
||||||
|
val structure = parametersStructure[i]
|
||||||
|
if (structure is MultiFieldValueClassMapping) {
|
||||||
|
newParamList[0].defaultValue = with(context.createJvmIrBuilder(replacement.symbol)) {
|
||||||
|
irExprBody(irBlock {
|
||||||
|
val mfvcNodeInstance = structure.rootMfvcNode.createInstanceFromValueDeclarationsAndBoxType(
|
||||||
|
param.type as IrSimpleType, newParamList
|
||||||
|
)
|
||||||
|
flattenExpressionTo(defaultValue, mfvcNodeInstance)
|
||||||
|
+irGet(newParamList[0])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitParameter(parameter: IrValueParameter) {
|
||||||
|
if (parameter.origin != IrDeclarationOrigin.GENERATED_MULTI_FIELD_VALUE_CLASS_PARAMETER) {
|
||||||
|
super.visitParameter(parameter)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun RootMfvcNode.replacePrimaryMultiFieldValueClassConstructor() {
|
fun RootMfvcNode.replacePrimaryMultiFieldValueClassConstructor() {
|
||||||
@@ -1033,12 +1065,14 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
|||||||
if (constructor.isPrimary && constructor.constructedClass.isMultiFieldValueClass &&
|
if (constructor.isPrimary && constructor.constructedClass.isMultiFieldValueClass &&
|
||||||
constructor.origin != JvmLoweredDeclarationOrigin.STATIC_MULTI_FIELD_VALUE_CLASS_CONSTRUCTOR
|
constructor.origin != JvmLoweredDeclarationOrigin.STATIC_MULTI_FIELD_VALUE_CLASS_CONSTRUCTOR
|
||||||
) {
|
) {
|
||||||
val oldArguments = List(expression.valueArgumentsCount) { expression.getValueArgument(it) }
|
val oldArguments = List(expression.valueArgumentsCount) {
|
||||||
|
expression.getValueArgument(it) ?: error("Default arguments for MFVC primary constructors are not yet supported")
|
||||||
|
}
|
||||||
require(rootNode.subnodes.size == oldArguments.size) {
|
require(rootNode.subnodes.size == oldArguments.size) {
|
||||||
"Old ${constructor.render()} must have ${rootNode.subnodes.size} arguments but got ${oldArguments.size}"
|
"Old ${constructor.render()} must have ${rootNode.subnodes.size} arguments but got ${oldArguments.size}"
|
||||||
}
|
}
|
||||||
for ((subnode, argument) in rootNode.subnodes zip oldArguments) {
|
for ((subnode, argument) in rootNode.subnodes zip oldArguments) {
|
||||||
argument?.let { flattenExpressionTo(it, instance[subnode.name]!!) }
|
flattenExpressionTo(argument, instance[subnode.name]!!)
|
||||||
}
|
}
|
||||||
+irCall(rootNode.primaryConstructorImpl).apply {
|
+irCall(rootNode.primaryConstructorImpl).apply {
|
||||||
copyTypeArgumentsFrom(expression)
|
copyTypeArgumentsFrom(expression)
|
||||||
@@ -1143,18 +1177,26 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
|||||||
}
|
}
|
||||||
|
|
||||||
private sealed class BlockOrBody {
|
private sealed class BlockOrBody {
|
||||||
data class Body(val body: IrBody) : BlockOrBody()
|
abstract val element: IrElement
|
||||||
data class Block(val block: IrBlock) : BlockOrBody()
|
|
||||||
|
data class Body(val body: IrBody) : BlockOrBody() {
|
||||||
|
override val element get() = body
|
||||||
|
}
|
||||||
|
|
||||||
|
data class Block(val block: IrBlock) : BlockOrBody() {
|
||||||
|
override val element get() = block
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds the most narrow block or body which contains all usages of each of the given variables
|
* Finds the most narrow block or body which contains all usages of each of the given variables
|
||||||
*/
|
*/
|
||||||
private fun findNearestBlocksForVariables(variables: Set<IrVariable>, body: IrBody): Map<IrVariable, BlockOrBody?> {
|
private fun findNearestBlocksForVariables(variables: Set<IrVariable>, body: BlockOrBody): Map<IrVariable, BlockOrBody?> {
|
||||||
|
if (variables.isEmpty()) return mapOf()
|
||||||
val variableUsages = mutableMapOf<BlockOrBody, MutableSet<IrVariable>>()
|
val variableUsages = mutableMapOf<BlockOrBody, MutableSet<IrVariable>>()
|
||||||
val childrenBlocks = mutableMapOf<BlockOrBody, MutableList<BlockOrBody>>()
|
val childrenBlocks = mutableMapOf<BlockOrBody, MutableList<BlockOrBody>>()
|
||||||
|
|
||||||
body.acceptVoid(object : IrElementVisitorVoid {
|
body.element.acceptVoid(object : IrElementVisitorVoid {
|
||||||
private val stack = mutableListOf<BlockOrBody>()
|
private val stack = mutableListOf<BlockOrBody>()
|
||||||
override fun visitElement(element: IrElement) {
|
override fun visitElement(element: IrElement) {
|
||||||
element.acceptChildren(this, null)
|
element.acceptChildren(this, null)
|
||||||
@@ -1168,7 +1210,7 @@ private fun findNearestBlocksForVariables(variables: Set<IrVariable>, body: IrBo
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visitBlock(expression: IrBlock) {
|
override fun visitBlock(expression: IrBlock) {
|
||||||
childrenBlocks.getOrPut(currentStackElement()!!) { mutableListOf() }.add(Block(expression))
|
currentStackElement()?.let { childrenBlocks.getOrPut(it) { mutableListOf() }.add(Block(expression)) }
|
||||||
stack.add(Block(expression))
|
stack.add(Block(expression))
|
||||||
super.visitBlock(expression)
|
super.visitBlock(expression)
|
||||||
require(stack.removeLast() == Block(expression)) { "Invalid stack" }
|
require(stack.removeLast() == Block(expression)) { "Invalid stack" }
|
||||||
@@ -1195,7 +1237,7 @@ private fun findNearestBlocksForVariables(variables: Set<IrVariable>, body: IrBo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return variables.associateWith { dfs(BlockOrBody.Body(body), it) }
|
return variables.associateWith { dfs(body, it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun IrStatement.containsUsagesOf(variablesSet: Set<IrVariable>): Boolean {
|
private fun IrStatement.containsUsagesOf(variablesSet: Set<IrVariable>): Boolean {
|
||||||
@@ -1217,20 +1259,20 @@ private fun IrStatement.containsUsagesOf(variablesSet: Set<IrVariable>): Boolean
|
|||||||
return used
|
return used
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun IrBody.makeBodyWithAddedVariables(context: JvmBackendContext, variables: Set<IrVariable>, symbol: IrSymbol) =
|
||||||
|
BlockOrBody.Body(this).makeBodyWithAddedVariables(context, variables, symbol) as IrBody
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds declarations of the variables to the most narrow possible block or body.
|
* Adds declarations of the variables to the most narrow possible block or body.
|
||||||
* It adds them before the first usage within the block and inlines initialization of them when possible.
|
* It adds them before the first usage within the block and inlines initialization of them when possible.
|
||||||
*/
|
*/
|
||||||
fun IrBody.makeBodyWithAddedVariables(
|
private fun BlockOrBody.makeBodyWithAddedVariables(context: JvmBackendContext, variables: Set<IrVariable>, symbol: IrSymbol): IrElement {
|
||||||
context: JvmBackendContext,
|
if (variables.isEmpty()) return element
|
||||||
variables: Set<IrVariable>,
|
|
||||||
symbol: IrSymbol
|
|
||||||
): IrBody {
|
|
||||||
val nearestBlocks = findNearestBlocksForVariables(variables, this)
|
val nearestBlocks = findNearestBlocksForVariables(variables, this)
|
||||||
val containingVariables: Map<BlockOrBody, List<IrVariable>> = nearestBlocks.entries
|
val containingVariables: Map<BlockOrBody, List<IrVariable>> = nearestBlocks.entries
|
||||||
.mapNotNull { (k, v) -> if (v != null) k to v else null }
|
.mapNotNull { (k, v) -> if (v != null) k to v else null }
|
||||||
.groupBy({ (_, v) -> v }, { (k, _) -> k })
|
.groupBy({ (_, v) -> v }, { (k, _) -> k })
|
||||||
return transform(object : IrElementTransformerVoid() {
|
return element.transform(object : IrElementTransformerVoid() {
|
||||||
private fun getFlattenedStatements(container: IrStatementContainer): Sequence<IrStatement> = sequence {
|
private fun getFlattenedStatements(container: IrStatementContainer): Sequence<IrStatement> = sequence {
|
||||||
for (statement in container.statements) {
|
for (statement in container.statements) {
|
||||||
if (statement is IrStatementContainer) {
|
if (statement is IrStatementContainer) {
|
||||||
@@ -1306,12 +1348,11 @@ fun IrBody.makeBodyWithAddedVariables(
|
|||||||
override fun visitExpressionBody(body: IrExpressionBody): IrBody {
|
override fun visitExpressionBody(body: IrExpressionBody): IrBody {
|
||||||
val lowering = this
|
val lowering = this
|
||||||
containingVariables[BlockOrBody.Body(body)]?.takeIf { it.isNotEmpty() }?.let { bodyVars ->
|
containingVariables[BlockOrBody.Body(body)]?.takeIf { it.isNotEmpty() }?.let { bodyVars ->
|
||||||
val blockBody = context.createJvmIrBuilder(symbol).irBlockBody {
|
return with(context.createJvmIrBuilder(symbol)) {
|
||||||
+irReturn(body.expression.transform(lowering, null))
|
val blockBody = irBlock { +body.expression.transform(lowering, null) }
|
||||||
|
replaceSetVariableWithInitialization(bodyVars, blockBody)
|
||||||
|
irExprBody(blockBody)
|
||||||
}
|
}
|
||||||
blockBody.transformChildrenVoid()
|
|
||||||
replaceSetVariableWithInitialization(bodyVars, blockBody)
|
|
||||||
return blockBody
|
|
||||||
}
|
}
|
||||||
return super.visitExpressionBody(body)
|
return super.visitExpressionBody(body)
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-3
@@ -89,7 +89,7 @@ internal abstract class JvmValueClassAbstractLowering(val context: JvmBackendCon
|
|||||||
|
|
||||||
private fun transformFlattenedConstructor(function: IrConstructor, replacement: IrConstructor): List<IrDeclaration>? {
|
private fun transformFlattenedConstructor(function: IrConstructor, replacement: IrConstructor): List<IrDeclaration>? {
|
||||||
replacement.valueParameters.forEach {
|
replacement.valueParameters.forEach {
|
||||||
it.transformChildrenVoid()
|
visitParameter(it)
|
||||||
it.defaultValue?.patchDeclarationParents(replacement)
|
it.defaultValue?.patchDeclarationParents(replacement)
|
||||||
}
|
}
|
||||||
allScopes.push(createScope(function))
|
allScopes.push(createScope(function))
|
||||||
@@ -106,9 +106,18 @@ internal abstract class JvmValueClassAbstractLowering(val context: JvmBackendCon
|
|||||||
|
|
||||||
protected abstract fun transformSecondaryConstructorFlat(constructor: IrConstructor, replacement: IrSimpleFunction): List<IrDeclaration>
|
protected abstract fun transformSecondaryConstructorFlat(constructor: IrConstructor, replacement: IrSimpleFunction): List<IrDeclaration>
|
||||||
|
|
||||||
|
open fun visitParameter(parameter: IrValueParameter) {
|
||||||
|
parameter.transformChildrenVoid()
|
||||||
|
}
|
||||||
|
|
||||||
|
final override fun visitValueParameterNew(declaration: IrValueParameter): IrStatement {
|
||||||
|
visitParameter(declaration)
|
||||||
|
return declaration
|
||||||
|
}
|
||||||
|
|
||||||
private fun transformSimpleFunctionFlat(function: IrSimpleFunction, replacement: IrSimpleFunction): List<IrDeclaration> {
|
private fun transformSimpleFunctionFlat(function: IrSimpleFunction, replacement: IrSimpleFunction): List<IrDeclaration> {
|
||||||
replacement.valueParameters.forEach {
|
replacement.valueParameters.forEach {
|
||||||
it.transformChildrenVoid()
|
visitParameter(it)
|
||||||
it.defaultValue?.patchDeclarationParents(replacement)
|
it.defaultValue?.patchDeclarationParents(replacement)
|
||||||
}
|
}
|
||||||
allScopes.push(createScope(replacement))
|
allScopes.push(createScope(replacement))
|
||||||
@@ -184,7 +193,11 @@ internal abstract class JvmValueClassAbstractLowering(val context: JvmBackendCon
|
|||||||
function,
|
function,
|
||||||
replacement,
|
replacement,
|
||||||
when {
|
when {
|
||||||
function.isTypedEquals() -> InlineClassAbi.mangledNameFor(function, mangleReturnTypes = false, useOldMangleRules = false)
|
function.isValueClassTypedEquals -> InlineClassAbi.mangledNameFor(
|
||||||
|
function,
|
||||||
|
mangleReturnTypes = false,
|
||||||
|
useOldMangleRules = false
|
||||||
|
)
|
||||||
// If the original function has signature which need mangling we still need to replace it with a mangled version.
|
// If the original function has signature which need mangling we still need to replace it with a mangled version.
|
||||||
(!function.isFakeOverride || function.findInterfaceImplementation(context.state.jvmDefaultMode) != null) && when (specificMangle) {
|
(!function.isFakeOverride || function.findInterfaceImplementation(context.state.jvmDefaultMode) != null) && when (specificMangle) {
|
||||||
SpecificMangle.Inline -> function.signatureRequiresMangling(includeInline = true, includeMFVC = false)
|
SpecificMangle.Inline -> function.signatureRequiresMangling(includeInline = true, includeMFVC = false)
|
||||||
|
|||||||
+22
-14
@@ -6,14 +6,14 @@
|
|||||||
package org.jetbrains.kotlin.backend.jvm
|
package org.jetbrains.kotlin.backend.jvm
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.jvm.MemoizedMultiFieldValueClassReplacements.RemappedParameter.MultiFieldValueClassMapping
|
import org.jetbrains.kotlin.backend.jvm.MemoizedMultiFieldValueClassReplacements.RemappedParameter.MultiFieldValueClassMapping
|
||||||
import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
|
import org.jetbrains.kotlin.backend.jvm.ir.*
|
||||||
import org.jetbrains.kotlin.backend.jvm.ir.extensionReceiverName
|
|
||||||
import org.jetbrains.kotlin.backend.jvm.ir.findSuperDeclaration
|
|
||||||
import org.jetbrains.kotlin.backend.jvm.ir.isStaticValueClassReplacement
|
|
||||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||||
import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
|
import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
|
||||||
import org.jetbrains.kotlin.ir.builders.declarations.buildConstructor
|
import org.jetbrains.kotlin.ir.builders.declarations.buildConstructor
|
||||||
|
import org.jetbrains.kotlin.ir.builders.irExprBody
|
||||||
|
import org.jetbrains.kotlin.ir.builders.irGet
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||||
import org.jetbrains.kotlin.ir.types.IrSimpleType
|
import org.jetbrains.kotlin.ir.types.IrSimpleType
|
||||||
@@ -44,29 +44,34 @@ class MemoizedMultiFieldValueClassReplacements(
|
|||||||
targetFunction: IrFunction,
|
targetFunction: IrFunction,
|
||||||
originWhenFlattened: IrDeclarationOrigin,
|
originWhenFlattened: IrDeclarationOrigin,
|
||||||
): RemappedParameter {
|
): RemappedParameter {
|
||||||
|
val oldParam = this
|
||||||
if (!type.needsMfvcFlattening()) return RemappedParameter.RegularMapping(
|
if (!type.needsMfvcFlattening()) return RemappedParameter.RegularMapping(
|
||||||
targetFunction.addValueParameter {
|
targetFunction.addValueParameter {
|
||||||
updateFrom(this@grouped)
|
updateFrom(oldParam)
|
||||||
this.name = this@grouped.name
|
this.name = oldParam.name
|
||||||
index = targetFunction.valueParameters.size
|
index = targetFunction.valueParameters.size
|
||||||
}.apply {
|
}.apply {
|
||||||
copyAnnotationsFrom(this@grouped)
|
defaultValue = oldParam.defaultValue
|
||||||
|
copyAnnotationsFrom(oldParam)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
val rootMfvcNode = this@MemoizedMultiFieldValueClassReplacements.getRootMfvcNode(type.erasedUpperBound)!!
|
val rootMfvcNode = this@MemoizedMultiFieldValueClassReplacements.getRootMfvcNode(type.erasedUpperBound)
|
||||||
require(!hasDefaultValue()) { "Default parameters values are not supported for multi-field value classes" }
|
defaultValue?.expression?.let { oldMfvcDefaultArguments.putIfAbsent(this, it) }
|
||||||
val newType = type.substitute(substitutionMap) as IrSimpleType
|
val newType = type.substitute(substitutionMap) as IrSimpleType
|
||||||
val localSubstitutionMap = makeTypeArgumentsFromType(newType)
|
val localSubstitutionMap = makeTypeArgumentsFromType(newType)
|
||||||
val valueParameters = rootMfvcNode.mapLeaves { leaf ->
|
val valueParameters = rootMfvcNode.mapLeaves { leaf ->
|
||||||
targetFunction.addValueParameter {
|
targetFunction.addValueParameter {
|
||||||
updateFrom(this@grouped)
|
updateFrom(oldParam)
|
||||||
this.name = Name.identifier("${name ?: this@grouped.name}-${leaf.fullFieldName}")
|
this.name = Name.identifier("${name ?: oldParam.name}-${leaf.fullFieldName}")
|
||||||
type = leaf.type.substitute(localSubstitutionMap)
|
type = leaf.type.substitute(localSubstitutionMap)
|
||||||
origin = originWhenFlattened
|
origin = originWhenFlattened
|
||||||
index = targetFunction.valueParameters.size
|
index = targetFunction.valueParameters.size
|
||||||
}.apply {
|
isAssignable = isAssignable || oldParam.defaultValue != null
|
||||||
defaultValue = null
|
}.also { newParam ->
|
||||||
copyAnnotationsFrom(this@grouped)
|
newParam.defaultValue = oldParam.defaultValue?.let {
|
||||||
|
context.createJvmIrBuilder(targetFunction.symbol).run { irExprBody(irGet(newParam)) }
|
||||||
|
}
|
||||||
|
require(oldParam.annotations.isEmpty()) { "Annotations are not supported for MFVC parameters" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return MultiFieldValueClassMapping(rootMfvcNode, newType, valueParameters)
|
return MultiFieldValueClassMapping(rootMfvcNode, newType, valueParameters)
|
||||||
@@ -79,6 +84,9 @@ class MemoizedMultiFieldValueClassReplacements(
|
|||||||
originWhenFlattened: IrDeclarationOrigin,
|
originWhenFlattened: IrDeclarationOrigin,
|
||||||
): List<RemappedParameter> = map { it.grouped(name, substitutionMap, targetFunction, originWhenFlattened) }
|
): List<RemappedParameter> = map { it.grouped(name, substitutionMap, targetFunction, originWhenFlattened) }
|
||||||
|
|
||||||
|
|
||||||
|
val oldMfvcDefaultArguments = ConcurrentHashMap<IrValueParameter, IrExpression>()
|
||||||
|
|
||||||
private fun buildReplacement(
|
private fun buildReplacement(
|
||||||
function: IrFunction,
|
function: IrFunction,
|
||||||
replacementOrigin: IrDeclarationOrigin,
|
replacementOrigin: IrDeclarationOrigin,
|
||||||
|
|||||||
@@ -0,0 +1,91 @@
|
|||||||
|
// CHECK_BYTECODE_LISTING
|
||||||
|
// WITH_STDLIB
|
||||||
|
// TARGET_BACKEND: JVM_IR
|
||||||
|
// WORKS_WHEN_VALUE_CLASS
|
||||||
|
// LANGUAGE: +ValueClasses
|
||||||
|
|
||||||
|
@JvmInline
|
||||||
|
value class DPoint(/*inline */val x: Double/* = 1.0*/, /*inline */val y: Double/* = 2.0*/) {
|
||||||
|
fun f1(a: Int, b: Int = -1, c: DPoint = DPoint(-2.0, -3.0)) = listOf(this, x, y, a, b, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmInline
|
||||||
|
value class DSegment(/*inline */val p1: DPoint/* = DPoint(3.0, 4.0)*/, /*inline */val p2: DPoint/* = DPoint(5.0, 6.0)*/, /*inline */val n: Int/* = 7*/) {
|
||||||
|
fun f2(a: Int, b: Int = -1, c: DPoint = DPoint(-2.0, -3.0)) = listOf(this, p1, p2, n, a, b, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
data class Wrapper(val segment: DSegment = DSegment(DPoint(8.0, 9.0), DPoint(10.0, 11.0), 7), val n: Int = 12) {
|
||||||
|
fun f3(a: Int, b: Int = -1, c: DPoint = DPoint(-2.0, -3.0)) = listOf(this, segment, n, a, b, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun complexFun(a1: Double, a2: DPoint, a3: Double = a1 * a2.x * a2.y, a4: DPoint = DPoint(a2.x * a1 * a3, a2.y * a1 * a3)) = "$a1, $a2, $a3, $a4"
|
||||||
|
|
||||||
|
inline fun complexInlineFun(a1: Double, a2: DPoint, a3: Double = a1 * a2.x * a2.y, a4: DPoint = DPoint(a2.x * a1 * a3, a2.y * a1 * a3)) = "$a1, $a2, $a3, $a4"
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
// comments bellow are because MFVC primary constructors default parameters require support of inline arguments in regular functions
|
||||||
|
// require(DPoint() == DPoint(1.0, 2.0)) { "${DPoint()} ${DPoint(1.0, 2.0)}" }
|
||||||
|
// require(DPoint(3.0) == DPoint(3.0, 2.0)) { "${DPoint()} ${DPoint(3.0, 2.0)}" }
|
||||||
|
// require(DPoint(x = 3.0) == DPoint(3.0, 2.0)) { "${DPoint()} ${DPoint(3.0, 2.0)}" }
|
||||||
|
// require(DPoint(y = 3.0) == DPoint(1.0, 3.0)) { "${DPoint()} ${DPoint(1.0, 3.0)}" }
|
||||||
|
// val defaultDPoint = DPoint()
|
||||||
|
val defaultDPoint = DPoint(1.0, 2.0)
|
||||||
|
require(defaultDPoint.f1(4) == listOf(DPoint(1.0, 2.0), 1.0, 2.0, 4, -1, DPoint(-2.0, -3.0))) {
|
||||||
|
defaultDPoint.f1(4).toString()
|
||||||
|
}
|
||||||
|
require(defaultDPoint.f1(4, 1, DPoint(2.0, 3.0)) == listOf(DPoint(1.0, 2.0), 1.0, 2.0, 4, 1, DPoint(2.0, 3.0))) {
|
||||||
|
defaultDPoint.f1(4, 1, DPoint(2.0, 3.0)).toString()
|
||||||
|
}
|
||||||
|
require(DPoint(-1.0, -2.0).f1(4) == listOf(DPoint(-1.0, -2.0), -1.0, -2.0, 4, -1, DPoint(-2.0, -3.0))) {
|
||||||
|
defaultDPoint.f1(4).toString()
|
||||||
|
}
|
||||||
|
require(DPoint(-1.0, -2.0).f1(4, 1, DPoint(2.0, 3.0)) == listOf(DPoint(-1.0, -2.0), -1.0, -2.0, 4, 1, DPoint(2.0, 3.0))) {
|
||||||
|
defaultDPoint.f1(4, 1, DPoint(2.0, 3.0)).toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
// require(DSegment() == DSegment(DPoint(3.0, 4.0), DPoint(5.0, 6.0), 7)) { DSegment().toString() }
|
||||||
|
// val defaultDSegment = DSegment()
|
||||||
|
val defaultDSegment = DSegment(DPoint(3.0, 4.0), DPoint(5.0, 6.0), 7)
|
||||||
|
require(defaultDSegment.f2(100) == listOf(defaultDSegment, DPoint(3.0, 4.0), DPoint(5.0, 6.0), 7, 100, -1, DPoint(-2.0, -3.0))) {
|
||||||
|
defaultDSegment.f2(100).toString()
|
||||||
|
}
|
||||||
|
require(defaultDSegment.f2(100, b = 1) == listOf(defaultDSegment, DPoint(3.0, 4.0), DPoint(5.0, 6.0), 7, 100, 1, DPoint(-2.0, -3.0))) {
|
||||||
|
defaultDSegment.f2(100, b = 1).toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
require(Wrapper() == Wrapper(DSegment(DPoint(8.0, 9.0), DPoint(10.0, 11.0), 7), 12)) { Wrapper().toString() }
|
||||||
|
require(Wrapper().f3(100) == listOf(Wrapper(), DSegment(DPoint(8.0, 9.0), DPoint(10.0, 11.0), 7), 12, 100, -1, DPoint(-2.0, -3.0))) {
|
||||||
|
Wrapper().f3(100).toString()
|
||||||
|
}
|
||||||
|
require(Wrapper().f3(100, b = 1) == listOf(Wrapper(), DSegment(DPoint(8.0, 9.0), DPoint(10.0, 11.0), 7), 12, 100, 1, DPoint(-2.0, -3.0))) {
|
||||||
|
Wrapper().f3(100, b = 1).toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
require(complexFun(2.0, DPoint(3.0, 5.0)) == "2.0, ${DPoint(3.0, 5.0)}, 30.0, ${DPoint(180.0, 300.0)}") {
|
||||||
|
complexFun(2.0, DPoint(3.0, 5.0))
|
||||||
|
}
|
||||||
|
require(complexFun(2.0, DPoint(3.0, 5.0), 7.0) == "2.0, ${DPoint(3.0, 5.0)}, 7.0, ${DPoint(42.0, 70.0)}") {
|
||||||
|
complexFun(2.0, DPoint(3.0, 5.0), 7.0)
|
||||||
|
}
|
||||||
|
require(complexFun(2.0, DPoint(3.0, 5.0), a4 = DPoint(11.0, 13.0)) == "2.0, ${DPoint(3.0, 5.0)}, 30.0, ${DPoint(11.0, 13.0)}") {
|
||||||
|
complexFun(2.0, DPoint(3.0, 5.0), a4 = DPoint(11.0, 13.0))
|
||||||
|
}
|
||||||
|
require(complexFun(2.0, DPoint(3.0, 5.0), 7.0, DPoint(11.0, 13.0)) == "2.0, ${DPoint(3.0, 5.0)}, 7.0, ${DPoint(11.0, 13.0)}") {
|
||||||
|
complexFun(2.0, DPoint(3.0, 5.0), 7.0, DPoint(11.0, 13.0))
|
||||||
|
}
|
||||||
|
|
||||||
|
require(complexInlineFun(2.0, DPoint(3.0, 5.0)) == "2.0, ${DPoint(3.0, 5.0)}, 30.0, ${DPoint(180.0, 300.0)}") {
|
||||||
|
complexInlineFun(2.0, DPoint(3.0, 5.0))
|
||||||
|
}
|
||||||
|
require(complexInlineFun(2.0, DPoint(3.0, 5.0), 7.0) == "2.0, ${DPoint(3.0, 5.0)}, 7.0, ${DPoint(42.0, 70.0)}") {
|
||||||
|
complexInlineFun(2.0, DPoint(3.0, 5.0), 7.0)
|
||||||
|
}
|
||||||
|
require(complexInlineFun(2.0, DPoint(3.0, 5.0), a4 = DPoint(11.0, 13.0)) == "2.0, ${DPoint(3.0, 5.0)}, 30.0, ${DPoint(11.0, 13.0)}") {
|
||||||
|
complexInlineFun(2.0, DPoint(3.0, 5.0), a4 = DPoint(11.0, 13.0))
|
||||||
|
}
|
||||||
|
require(complexInlineFun(2.0, DPoint(3.0, 5.0), 7.0, DPoint(11.0, 13.0)) == "2.0, ${DPoint(3.0, 5.0)}, 7.0, ${DPoint(11.0, 13.0)}") {
|
||||||
|
complexInlineFun(2.0, DPoint(3.0, 5.0), 7.0, DPoint(11.0, 13.0))
|
||||||
|
}
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
@kotlin.jvm.JvmInline
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final class DPoint {
|
||||||
|
// source: 'defaultParameters.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): DPoint
|
||||||
|
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 synthetic static method f1-lIoT8es$default(p0: double, p1: double, p2: int, p3: int, p4: double, p5: double, p6: int, p7: java.lang.Object): java.util.List
|
||||||
|
public final static @org.jetbrains.annotations.NotNull method f1-lIoT8es(p0: double, p1: double, p2: int, p3: int, p4: double, p5: double): java.util.List
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.jvm.JvmInline
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final class DSegment {
|
||||||
|
// source: 'defaultParameters.kt'
|
||||||
|
private final field n: int
|
||||||
|
private final field p1-x: double
|
||||||
|
private final field p1-y: double
|
||||||
|
private final field p2-x: double
|
||||||
|
private final field p2-y: double
|
||||||
|
private synthetic method <init>(p0: double, p1: double, p2: double, p3: double, p4: int): void
|
||||||
|
public synthetic final static method box-impl(p0: double, p1: double, p2: double, p3: double, p4: int): DSegment
|
||||||
|
public final static method constructor-impl(p0: double, p1: double, p2: double, p3: double, p4: int): void
|
||||||
|
public method equals(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean
|
||||||
|
public static method equals-impl(p0: double, p1: double, p2: double, p3: double, p4: int, p5: java.lang.Object): boolean
|
||||||
|
public final static method equals-impl0(p0: double, p1: double, p2: double, p3: double, p4: int, p5: double, p6: double, p7: double, p8: double, p9: int): boolean
|
||||||
|
public synthetic static method f2-lIoT8es$default(p0: double, p1: double, p2: double, p3: double, p4: int, p5: int, p6: int, p7: double, p8: double, p9: int, p10: java.lang.Object): java.util.List
|
||||||
|
public final static @org.jetbrains.annotations.NotNull method f2-lIoT8es(p0: double, p1: double, p2: double, p3: double, p4: int, p5: int, p6: int, p7: double, p8: double): java.util.List
|
||||||
|
public final method getN(): int
|
||||||
|
public final @org.jetbrains.annotations.NotNull method getP1(): DPoint
|
||||||
|
public final @org.jetbrains.annotations.NotNull method getP2(): DPoint
|
||||||
|
public method hashCode(): int
|
||||||
|
public static method hashCode-impl(p0: double, p1: double, p2: double, p3: double, p4: int): int
|
||||||
|
public @org.jetbrains.annotations.NotNull method toString(): java.lang.String
|
||||||
|
public static method toString-impl(p0: double, p1: double, p2: double, p3: double, p4: int): java.lang.String
|
||||||
|
public synthetic final method unbox-impl-n(): int
|
||||||
|
public synthetic final method unbox-impl-p1(): DPoint
|
||||||
|
public synthetic final method unbox-impl-p1-x(): double
|
||||||
|
public synthetic final method unbox-impl-p1-y(): double
|
||||||
|
public synthetic final method unbox-impl-p2(): DPoint
|
||||||
|
public synthetic final method unbox-impl-p2-x(): double
|
||||||
|
public synthetic final method unbox-impl-p2-y(): double
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final class DefaultParametersKt {
|
||||||
|
// source: 'defaultParameters.kt'
|
||||||
|
public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String
|
||||||
|
public synthetic static method complexFun-552ch2I$default(p0: double, p1: double, p2: double, p3: double, p4: double, p5: double, p6: int, p7: java.lang.Object): java.lang.String
|
||||||
|
public final static @org.jetbrains.annotations.NotNull method complexFun-552ch2I(p0: double, p1: double, p2: double, p3: double, p4: double, p5: double): java.lang.String
|
||||||
|
public synthetic static method complexInlineFun-552ch2I$default(p0: double, p1: double, p2: double, p3: double, p4: double, p5: double, p6: int, p7: java.lang.Object): java.lang.String
|
||||||
|
public final static @org.jetbrains.annotations.NotNull method complexInlineFun-552ch2I(p0: double, p1: double, p2: double, p3: double, p4: double, p5: double): java.lang.String
|
||||||
|
public final inner class kotlin/jvm/internal/Ref$DoubleRef
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final class Wrapper {
|
||||||
|
// source: 'defaultParameters.kt'
|
||||||
|
private final field n: int
|
||||||
|
private final field segment-n: int
|
||||||
|
private final field segment-p1-x: double
|
||||||
|
private final field segment-p1-y: double
|
||||||
|
private final field segment-p2-x: double
|
||||||
|
private final field segment-p2-y: double
|
||||||
|
public method <init>(): void
|
||||||
|
public method <init>(p0: double, p1: double, p2: double, p3: double, p4: int, p5: int): void
|
||||||
|
public synthetic method <init>(p0: double, p1: double, p2: double, p3: double, p4: int, p5: int, p6: int, p7: kotlin.jvm.internal.DefaultConstructorMarker): void
|
||||||
|
public final @org.jetbrains.annotations.NotNull method component1(): DSegment
|
||||||
|
public final method component2(): int
|
||||||
|
public synthetic static method copy-GPBa7dw$default(p0: Wrapper, p1: double, p2: double, p3: double, p4: double, p5: int, p6: int, p7: int, p8: java.lang.Object): Wrapper
|
||||||
|
public final @org.jetbrains.annotations.NotNull method copy-GPBa7dw(p0: double, p1: double, p2: double, p3: double, p4: int, p5: int): Wrapper
|
||||||
|
public method equals(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean
|
||||||
|
public synthetic static method f3-lIoT8es$default(p0: Wrapper, p1: int, p2: int, p3: double, p4: double, p5: int, p6: java.lang.Object): java.util.List
|
||||||
|
public final @org.jetbrains.annotations.NotNull method f3-lIoT8es(p0: int, p1: int, p2: double, p3: double): java.util.List
|
||||||
|
public final method getN(): int
|
||||||
|
public final @org.jetbrains.annotations.NotNull method getSegment(): DSegment
|
||||||
|
public synthetic final method getSegment-n(): int
|
||||||
|
public synthetic final method getSegment-p1(): DPoint
|
||||||
|
public synthetic final method getSegment-p1-x(): double
|
||||||
|
public synthetic final method getSegment-p1-y(): double
|
||||||
|
public synthetic final method getSegment-p2(): DPoint
|
||||||
|
public synthetic final method getSegment-p2-x(): double
|
||||||
|
public synthetic final method getSegment-p2-y(): double
|
||||||
|
public method hashCode(): int
|
||||||
|
public @org.jetbrains.annotations.NotNull method toString(): java.lang.String
|
||||||
|
}
|
||||||
+6
@@ -50441,6 +50441,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
runTest("compiler/testData/codegen/box/valueClasses/conditionalExpressions.kt", TransformersFunctions.getReplaceOptionalJvmInlineAnnotationWithReal());
|
runTest("compiler/testData/codegen/box/valueClasses/conditionalExpressions.kt", TransformersFunctions.getReplaceOptionalJvmInlineAnnotationWithReal());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("defaultParameters.kt")
|
||||||
|
public void testDefaultParameters() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/valueClasses/defaultParameters.kt", TransformersFunctions.getReplaceOptionalJvmInlineAnnotationWithReal());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("equality.kt")
|
@TestMetadata("equality.kt")
|
||||||
public void testEquality() throws Exception {
|
public void testEquality() throws Exception {
|
||||||
|
|||||||
Reference in New Issue
Block a user