[IR] Fix bugs in MFVC function references support
Signed-off-by: Evgeniy.Zhelenskiy <Evgeniy.Zhelenskiy@jetbrains.com> #KT-1179
This commit is contained in:
committed by
Space Team
parent
86809e898a
commit
b7f249cdb6
+5
@@ -72,6 +72,11 @@ interface CommonBackendContext : BackendContext, LoggingContext, ErrorReportingC
|
||||
val optimizeNullChecksUsingKotlinNullability: Boolean
|
||||
get() = true
|
||||
|
||||
fun remapMultiFieldValueClassStructure(
|
||||
oldFunction: IrFunction, newFunction: IrFunction,
|
||||
parametersMappingOrNull: Map<IrValueParameter, IrValueParameter>?
|
||||
) = Unit
|
||||
|
||||
/**
|
||||
* See [InlineClassesUtils].
|
||||
*/
|
||||
|
||||
+4
-7
@@ -9,15 +9,11 @@ import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
||||
import org.jetbrains.kotlin.backend.common.DeclarationTransformer
|
||||
import org.jetbrains.kotlin.backend.common.descriptors.synthesizedString
|
||||
import org.jetbrains.kotlin.backend.common.ir.*
|
||||
import org.jetbrains.kotlin.backend.common.ir.ValueRemapper
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibility
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildConstructor
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||
@@ -32,7 +28,6 @@ import org.jetbrains.kotlin.ir.types.makeNullable
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
|
||||
// TODO: fix expect/actual default parameters
|
||||
@@ -521,7 +516,9 @@ private class MaskedDefaultArgumentFunctionFactory(context: CommonBackendContext
|
||||
IrDeclarationOrigin.METHOD_HANDLER_IN_DEFAULT_FUNCTION
|
||||
)
|
||||
}
|
||||
|
||||
context.remapMultiFieldValueClassStructure(
|
||||
original, this, parametersMappingOrNull = original.explicitParameters.zip(explicitParameters).toMap()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+5
@@ -705,6 +705,11 @@ class LocalDeclarationsLowering(
|
||||
isExplicitLocalFunction = oldDeclaration.origin == IrDeclarationOrigin.LOCAL_FUNCTION
|
||||
)
|
||||
newDeclaration.recordTransformedValueParameters(localFunctionContext)
|
||||
val parametersMapping = buildMap {
|
||||
oldDeclaration.extensionReceiverParameter?.let { put(it, newDeclaration.extensionReceiverParameter!!) }
|
||||
putAll(oldDeclaration.valueParameters zip newDeclaration.valueParameters.takeLast(oldDeclaration.valueParameters.size))
|
||||
}
|
||||
context.remapMultiFieldValueClassStructure(oldDeclaration, newDeclaration, parametersMapping)
|
||||
|
||||
newDeclaration.annotations = oldDeclaration.annotations
|
||||
|
||||
|
||||
+5
-1
@@ -6,8 +6,10 @@
|
||||
package org.jetbrains.kotlin.backend.jvm.intrinsics
|
||||
|
||||
import org.jetbrains.kotlin.backend.jvm.codegen.*
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.IrBlock
|
||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionReference
|
||||
import org.jetbrains.kotlin.ir.util.collectRealOverrides
|
||||
@@ -21,7 +23,9 @@ import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
*/
|
||||
object SignatureString : IntrinsicMethod() {
|
||||
override fun invoke(expression: IrFunctionAccessExpression, codegen: ExpressionCodegen, data: BlockInfo): PromisedValue {
|
||||
val function = (expression.getValueArgument(0) as IrFunctionReference).symbol.owner
|
||||
val argument = generateSequence(expression.getValueArgument(0) as IrStatement) { (it as? IrBlock)?.statements?.lastOrNull() }
|
||||
.filterIsInstance<IrFunctionReference>().single()
|
||||
val function = argument.symbol.owner
|
||||
generateSignatureString(codegen.mv, function, codegen.classCodegen)
|
||||
return MaterialValue(codegen, AsmTypes.JAVA_STRING_TYPE, codegen.context.irBuiltIns.stringType)
|
||||
}
|
||||
|
||||
+6
-1
@@ -340,6 +340,7 @@ private class AddContinuationLowering(context: JvmBackendContext) : SuspendLower
|
||||
}.apply {
|
||||
copyAnnotationsFrom(view)
|
||||
copyParameterDeclarationsFrom(view)
|
||||
context.remapMultiFieldValueClassStructure(view, this, parametersMappingOrNull = null)
|
||||
copyAttributes(view)
|
||||
generateErrorForInlineBody()
|
||||
}
|
||||
@@ -420,7 +421,7 @@ private fun IrSimpleFunction.createSuspendFunctionStub(context: JvmBackendContex
|
||||
function.valueParameters += valueParameters.take(index).map {
|
||||
it.copyTo(function, index = it.index, type = it.type.substitute(substitutionMap))
|
||||
}
|
||||
function.addValueParameter(
|
||||
val continuationParameter = function.addValueParameter(
|
||||
SUSPEND_FUNCTION_COMPLETION_PARAMETER_NAME,
|
||||
continuationType(context).substitute(substitutionMap),
|
||||
JvmLoweredDeclarationOrigin.CONTINUATION_CLASS
|
||||
@@ -428,6 +429,10 @@ private fun IrSimpleFunction.createSuspendFunctionStub(context: JvmBackendContex
|
||||
function.valueParameters += valueParameters.drop(index).map {
|
||||
it.copyTo(function, index = it.index + 1, type = it.type.substitute(substitutionMap))
|
||||
}
|
||||
context.remapMultiFieldValueClassStructure(
|
||||
this, function,
|
||||
parametersMappingOrNull = explicitParameters.zip(function.explicitParameters.filter { it != continuationParameter }).toMap()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-15
@@ -434,11 +434,7 @@ internal class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass
|
||||
}.apply {
|
||||
copyAttributes(target)
|
||||
copyParametersWithErasure(this@addBridge, bridge.overridden)
|
||||
with(context.multiFieldValueClassReplacements) {
|
||||
bindingNewFunctionToParameterTemplateStructure[bridge.overridden]?.also {
|
||||
bindingNewFunctionToParameterTemplateStructure[this@apply] = it
|
||||
}
|
||||
}
|
||||
context.remapMultiFieldValueClassStructure(bridge.overridden, this, parametersMappingOrNull = null)
|
||||
|
||||
// If target is a throwing stub, bridge also should just throw UnsupportedOperationException.
|
||||
// Otherwise, it might throw ClassCastException when downcasting bridge argument to expected type.
|
||||
@@ -494,11 +490,7 @@ internal class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass
|
||||
context.functionsWithSpecialBridges.add(target)
|
||||
|
||||
copyParametersWithErasure(this@addSpecialBridge, specialBridge.overridden, specialBridge.substitutedParameterTypes)
|
||||
with(context.multiFieldValueClassReplacements) {
|
||||
bindingNewFunctionToParameterTemplateStructure[specialBridge.overridden]?.also {
|
||||
bindingNewFunctionToParameterTemplateStructure[this@apply] = it
|
||||
}
|
||||
}
|
||||
context.remapMultiFieldValueClassStructure(specialBridge.overridden, this, parametersMappingOrNull = null)
|
||||
|
||||
body = context.createIrBuilder(symbol, startOffset, endOffset).irBlockBody {
|
||||
specialBridge.methodInfo?.let { info ->
|
||||
@@ -640,11 +632,7 @@ internal class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass
|
||||
}.unwrapBlock(), bridge.returnType.upperBound)
|
||||
|
||||
private fun getStructure(function: IrSimpleFunction): List<MemoizedMultiFieldValueClassReplacements.RemappedParameter>? {
|
||||
val mfvcOrOriginal = context.inlineClassReplacements.originalFunctionForMethodReplacement[function]
|
||||
?: context.inlineClassReplacements.originalFunctionForStaticReplacement[function]
|
||||
?: function
|
||||
val structure = context.multiFieldValueClassReplacements
|
||||
.bindingNewFunctionToParameterTemplateStructure[mfvcOrOriginal] ?: return null
|
||||
val structure = context.multiFieldValueClassReplacements.bindingNewFunctionToParameterTemplateStructure[function] ?: return null
|
||||
require(structure.sumOf { it.valueParameters.size } == function.explicitParametersCount) {
|
||||
"Bad parameters structure: $structure"
|
||||
}
|
||||
|
||||
+60
-60
@@ -81,78 +81,78 @@ private class FileClassLowering(val context: JvmBackendContext) : FileLoweringPa
|
||||
// TODO FirMetadataSource.File
|
||||
if (fileClassMembers.isEmpty() && (irFile.metadata as? DescriptorMetadataSource.File)?.descriptors.isNullOrEmpty()) return
|
||||
|
||||
val irFileClass = createFileClass(context, irFile, fileClassMembers)
|
||||
val irFileClass = createFileClass(irFile, fileClassMembers)
|
||||
classes.add(irFileClass)
|
||||
|
||||
irFile.declarations.clear()
|
||||
irFile.declarations.addAll(classes)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun createFileClass(context: JvmBackendContext, irFile: IrFile, fileClassMembers: List<IrDeclaration>): IrClass {
|
||||
val fileEntry = irFile.fileEntry
|
||||
val fileClassInfo = irFile.getFileClassInfo()
|
||||
val isMultifilePart = fileClassInfo.withJvmMultifileClass
|
||||
private fun createFileClass(irFile: IrFile, fileClassMembers: List<IrDeclaration>): IrClass {
|
||||
val fileEntry = irFile.fileEntry
|
||||
val fileClassInfo = irFile.getFileClassInfo()
|
||||
val isMultifilePart = fileClassInfo.withJvmMultifileClass
|
||||
|
||||
val onlyPrivateDeclarationsAndFeatureIsEnabled =
|
||||
context.state.languageVersionSettings.supportsFeature(LanguageFeature.PackagePrivateFileClassesWithAllPrivateMembers) && fileClassMembers
|
||||
.all {
|
||||
val isPrivate = it is IrDeclarationWithVisibility && DescriptorVisibilities.isPrivate(it.visibility)
|
||||
val isInlineOnly = it.hasAnnotation(INLINE_ONLY_ANNOTATION_FQ_NAME)
|
||||
isPrivate || isInlineOnly
|
||||
val onlyPrivateDeclarationsAndFeatureIsEnabled =
|
||||
context.state.languageVersionSettings.supportsFeature(LanguageFeature.PackagePrivateFileClassesWithAllPrivateMembers) && fileClassMembers
|
||||
.all {
|
||||
val isPrivate = it is IrDeclarationWithVisibility && DescriptorVisibilities.isPrivate(it.visibility)
|
||||
val isInlineOnly = it.hasAnnotation(INLINE_ONLY_ANNOTATION_FQ_NAME)
|
||||
isPrivate || isInlineOnly
|
||||
}
|
||||
|
||||
val fileClassOrigin =
|
||||
if (!isMultifilePart || context.state.languageVersionSettings.getFlag(JvmAnalysisFlags.inheritMultifileParts))
|
||||
IrDeclarationOrigin.FILE_CLASS
|
||||
else
|
||||
IrDeclarationOrigin.SYNTHETIC_FILE_CLASS
|
||||
return IrClassImpl(
|
||||
0, fileEntry.maxOffset,
|
||||
fileClassOrigin,
|
||||
symbol = IrClassSymbolImpl(),
|
||||
name = fileClassInfo.fileClassFqName.shortName(),
|
||||
kind = ClassKind.CLASS,
|
||||
visibility = if (isMultifilePart || onlyPrivateDeclarationsAndFeatureIsEnabled)
|
||||
JavaDescriptorVisibilities.PACKAGE_VISIBILITY
|
||||
else
|
||||
DescriptorVisibilities.PUBLIC,
|
||||
modality = Modality.FINAL
|
||||
).apply {
|
||||
superTypes = listOf(context.irBuiltIns.anyType)
|
||||
parent = irFile
|
||||
declarations.addAll(fileClassMembers)
|
||||
createImplicitParameterDeclarationWithWrappedDescriptor()
|
||||
for (member in fileClassMembers) {
|
||||
member.parent = this
|
||||
if (member is IrProperty) {
|
||||
member.getter?.let { it.parent = this }
|
||||
member.setter?.let { it.parent = this }
|
||||
member.backingField?.let { it.parent = this }
|
||||
}
|
||||
}
|
||||
|
||||
val fileClassOrigin =
|
||||
if (!isMultifilePart || context.state.languageVersionSettings.getFlag(JvmAnalysisFlags.inheritMultifileParts))
|
||||
IrDeclarationOrigin.FILE_CLASS
|
||||
else
|
||||
IrDeclarationOrigin.SYNTHETIC_FILE_CLASS
|
||||
return IrClassImpl(
|
||||
0, fileEntry.maxOffset,
|
||||
fileClassOrigin,
|
||||
symbol = IrClassSymbolImpl(),
|
||||
name = fileClassInfo.fileClassFqName.shortName(),
|
||||
kind = ClassKind.CLASS,
|
||||
visibility = if (isMultifilePart || onlyPrivateDeclarationsAndFeatureIsEnabled)
|
||||
JavaDescriptorVisibilities.PACKAGE_VISIBILITY
|
||||
else
|
||||
DescriptorVisibilities.PUBLIC,
|
||||
modality = Modality.FINAL
|
||||
).apply {
|
||||
superTypes = listOf(context.irBuiltIns.anyType)
|
||||
parent = irFile
|
||||
declarations.addAll(fileClassMembers)
|
||||
createImplicitParameterDeclarationWithWrappedDescriptor()
|
||||
for (member in fileClassMembers) {
|
||||
member.parent = this
|
||||
if (member is IrProperty) {
|
||||
member.getter?.let { it.parent = this }
|
||||
member.setter?.let { it.parent = this }
|
||||
member.backingField?.let { it.parent = this }
|
||||
annotations =
|
||||
if (isMultifilePart) irFile.annotations.filterNot {
|
||||
it.symbol.owner.parentAsClass.hasEqualFqName(JvmFileClassUtil.JVM_NAME)
|
||||
}
|
||||
else irFile.annotations
|
||||
|
||||
metadata = irFile.metadata
|
||||
|
||||
val partClassType = AsmUtil.asmTypeByFqNameWithoutInnerClasses(fileClassInfo.fileClassFqName)
|
||||
val facadeClassType =
|
||||
if (isMultifilePart) AsmUtil.asmTypeByFqNameWithoutInnerClasses(fileClassInfo.facadeClassFqName)
|
||||
else null
|
||||
context.state.factory.packagePartRegistry.addPart(irFile.fqName, partClassType.internalName, facadeClassType?.internalName)
|
||||
|
||||
if (fileClassInfo.fileClassFqName != fqNameWhenAvailable) {
|
||||
context.classNameOverride[this] = JvmClassName.byInternalName(partClassType.internalName)
|
||||
}
|
||||
}
|
||||
|
||||
annotations =
|
||||
if (isMultifilePart) irFile.annotations.filterNot {
|
||||
it.symbol.owner.parentAsClass.hasEqualFqName(JvmFileClassUtil.JVM_NAME)
|
||||
if (facadeClassType != null) {
|
||||
val jvmClassName = JvmClassName.byInternalName(facadeClassType.internalName)
|
||||
context.multifileFacadesToAdd.getOrPut(jvmClassName) { ArrayList() }.add(this)
|
||||
}
|
||||
else irFile.annotations
|
||||
|
||||
metadata = irFile.metadata
|
||||
|
||||
val partClassType = AsmUtil.asmTypeByFqNameWithoutInnerClasses(fileClassInfo.fileClassFqName)
|
||||
val facadeClassType =
|
||||
if (isMultifilePart) AsmUtil.asmTypeByFqNameWithoutInnerClasses(fileClassInfo.facadeClassFqName)
|
||||
else null
|
||||
context.state.factory.packagePartRegistry.addPart(irFile.fqName, partClassType.internalName, facadeClassType?.internalName)
|
||||
|
||||
if (fileClassInfo.fileClassFqName != fqNameWhenAvailable) {
|
||||
context.classNameOverride[this] = JvmClassName.byInternalName(partClassType.internalName)
|
||||
}
|
||||
|
||||
if (facadeClassType != null) {
|
||||
val jvmClassName = JvmClassName.byInternalName(facadeClassType.internalName)
|
||||
context.multifileFacadesToAdd.getOrPut(jvmClassName) { ArrayList() }.add(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-3
@@ -108,11 +108,9 @@ private class InheritedDefaultMethodsOnClassesLowering(val context: JvmBackendCo
|
||||
irFunction.dispatchReceiverParameter?.let {
|
||||
putValueArgument(0, irGet(it).reinterpretAsDispatchReceiverOfType(superClassType))
|
||||
}
|
||||
val mfvcOrOriginal = backendContext.inlineClassReplacements.originalFunctionForMethodReplacement[classOverride]
|
||||
?: classOverride
|
||||
val bindingNewFunctionToParameterTemplateStructure = backendContext.multiFieldValueClassReplacements
|
||||
.bindingNewFunctionToParameterTemplateStructure
|
||||
val structure = bindingNewFunctionToParameterTemplateStructure[mfvcOrOriginal]?.let { structure ->
|
||||
val structure = bindingNewFunctionToParameterTemplateStructure[classOverride]?.let { structure ->
|
||||
require(structure.sumOf { it.valueParameters.size } == classOverride.explicitParametersCount) {
|
||||
"Bad parameters structure: $structure"
|
||||
}
|
||||
|
||||
+1
-2
@@ -41,9 +41,8 @@ import org.jetbrains.kotlin.resolve.JVM_INLINE_ANNOTATION_FQ_NAME
|
||||
*/
|
||||
internal class JvmInlineClassLowering(
|
||||
context: JvmBackendContext,
|
||||
fileClassNewDeclarations: MutableMap<IrFile, MutableList<IrSimpleFunction>>,
|
||||
scopeStack: MutableList<ScopeWithIr>,
|
||||
) : JvmValueClassAbstractLowering(context, fileClassNewDeclarations, scopeStack) {
|
||||
) : JvmValueClassAbstractLowering(context, scopeStack) {
|
||||
override val replacements: MemoizedValueClassAbstractReplacements
|
||||
get() = context.inlineClassReplacements
|
||||
|
||||
|
||||
+109
-65
@@ -17,6 +17,8 @@ import org.jetbrains.kotlin.backend.jvm.MemoizedMultiFieldValueClassReplacements
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.createJvmIrBuilder
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.BlockOrBody.Block
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
@@ -37,9 +39,8 @@ import org.jetbrains.kotlin.name.Name
|
||||
|
||||
internal class JvmMultiFieldValueClassLowering(
|
||||
context: JvmBackendContext,
|
||||
fileClassNewDeclarations: MutableMap<IrFile, MutableList<IrSimpleFunction>>,
|
||||
scopeStack: MutableList<ScopeWithIr>,
|
||||
) : JvmValueClassAbstractLowering(context, fileClassNewDeclarations, scopeStack) {
|
||||
) : JvmValueClassAbstractLowering(context, scopeStack) {
|
||||
override val IrType.needsHandling: Boolean
|
||||
get() = needsMfvcFlattening()
|
||||
|
||||
@@ -292,22 +293,18 @@ internal class JvmMultiFieldValueClassLowering(
|
||||
override fun visitClassNewDeclarationsWhenParallel(declaration: IrDeclaration) =
|
||||
postActionAfterTransformingClassDeclaration(declaration)
|
||||
|
||||
private fun postActionAfterTransformingClassDeclaration(replacingDeclaration: IrDeclaration) {
|
||||
override fun postActionAfterTransformingClassDeclaration(replacingDeclaration: IrDeclaration) {
|
||||
when (replacingDeclaration) {
|
||||
is IrFunction -> replacingDeclaration.body = replacingDeclaration.body?.makeBodyWithAddedVariables(
|
||||
context, variablesToAdd[replacingDeclaration] ?: emptySet(), replacingDeclaration.symbol
|
||||
)?.apply {
|
||||
if (replacingDeclaration in possibleExtraBoxUsageGenerated) {
|
||||
removeAllExtraBoxes()
|
||||
}
|
||||
if (replacingDeclaration in possibleExtraBoxUsageGenerated) removeAllExtraBoxes()
|
||||
}
|
||||
|
||||
is IrAnonymousInitializer -> replacingDeclaration.body = replacingDeclaration.body.makeBodyWithAddedVariables(
|
||||
context, variablesToAdd[replacingDeclaration.parent] ?: emptySet(), replacingDeclaration.symbol
|
||||
).apply {
|
||||
if (replacingDeclaration in possibleExtraBoxUsageGenerated) {
|
||||
removeAllExtraBoxes()
|
||||
}
|
||||
if (replacingDeclaration in possibleExtraBoxUsageGenerated) removeAllExtraBoxes()
|
||||
} as IrBlockBody
|
||||
|
||||
else -> Unit
|
||||
@@ -487,10 +484,8 @@ internal class JvmMultiFieldValueClassLowering(
|
||||
valueParameters = replacement.valueParameters.drop(offset).map {
|
||||
it.copyTo(this, type = it.type.substitute(substitutionMap), index = it.index - offset)
|
||||
}
|
||||
val bridgeStructure = replacementStructure.toMutableList().apply {
|
||||
set(0, RegularMapping(dispatchReceiverParameter!!))
|
||||
}
|
||||
replacements.bindingNewFunctionToParameterTemplateStructure[this] = bridgeStructure
|
||||
val parametersMapping = (replacement.valueParameters.drop(offset) zip valueParameters).toMap()
|
||||
context.remapMultiFieldValueClassStructure(replacement, this, parametersMapping)
|
||||
} else {
|
||||
copyParameterDeclarationsFrom(source)
|
||||
}
|
||||
@@ -726,63 +721,112 @@ internal class JvmMultiFieldValueClassLowering(
|
||||
mfvc.declarations.removeIf { it is IrAnonymousInitializer }
|
||||
}
|
||||
|
||||
private val mfvcConstructorRefReplacements = mutableMapOf<Pair<IrFile, MfvcNode>, IrSimpleFunction>()
|
||||
private fun IrBlock.hasLambdaLikeOrigin() = origin == IrStatementOrigin.LAMBDA || origin == IrStatementOrigin.ANONYMOUS_FUNCTION
|
||||
|
||||
override fun visitFunctionReference(expression: IrFunctionReference): IrExpression {
|
||||
val function = expression.symbol.owner
|
||||
val replacement = function.let {
|
||||
replacements.run {
|
||||
getReplacementFunction(it) ?: if (it is IrConstructor) getReplacementForRegularClassConstructor(it) else null
|
||||
}
|
||||
} ?: return super.visitFunctionReference(expression)
|
||||
return if (function is IrConstructor && function.isPrimary && function.constructedClass.isMultiFieldValueClass) {
|
||||
val rootNode = replacements.getRootMfvcNode(function.constructedClass)
|
||||
val newFunction: IrSimpleFunction = mfvcConstructorRefReplacements.getOrPut(currentFile to rootNode) {
|
||||
createMfvcPrimaryConstructorReferenceHelperFunction(rootNode)
|
||||
}
|
||||
IrFunctionReferenceImpl(
|
||||
expression.startOffset, expression.endOffset,
|
||||
newFunction.returnType, newFunction.symbol, function.typeParameters.size, replacement.valueParameters.size,
|
||||
newFunction.symbol, expression.origin
|
||||
)
|
||||
} else {
|
||||
context.createJvmIrBuilder(getCurrentScopeSymbol()).irBlock {
|
||||
expression.apply {
|
||||
buildReplacement(function, expression, replacement) {
|
||||
IrFunctionReferenceImpl(
|
||||
startOffset, endOffset,
|
||||
type, it, function.typeParameters.size, replacement.valueParameters.size,
|
||||
reflectionTarget, origin
|
||||
)
|
||||
}.copyAttributes(expression)
|
||||
}
|
||||
}.unwrapBlock()
|
||||
override fun visitContainerExpression(expression: IrContainerExpression): IrExpression {
|
||||
if (expression is IrBlock && expression.hasLambdaLikeOrigin() && expression.statements.any { it is IrFunctionReference }) {
|
||||
return visitLambda(expression)
|
||||
}
|
||||
return super.visitContainerExpression(expression)
|
||||
}
|
||||
|
||||
private fun createMfvcPrimaryConstructorReferenceHelperFunction(rootNode: RootMfvcNode): IrSimpleFunction {
|
||||
val currentFile = currentFile
|
||||
return context.irFactory.buildFun {
|
||||
name = Name.identifier("mfvcConstructorReferenceHelper\$${fileClassNewDeclarations[currentFile]?.size ?: 0}")
|
||||
origin = JvmLoweredDeclarationOrigin.MFVC_PRIMARY_CONSTRUCTOR_REFERENCE_HELPER
|
||||
}.apply function@{
|
||||
parent = currentFile
|
||||
fileClassNewDeclarations.getOrPut(currentFile) { mutableListOf() }.add(this)
|
||||
copyParameterDeclarationsFrom(rootNode.primaryConstructorImpl)
|
||||
returnType = rootNode.type.substitute(rootNode.mfvc.typeParameters, typeParameters.map { it.defaultType })
|
||||
body = context.createJvmIrBuilder(this.symbol).run {
|
||||
irExprBody(irBlock {
|
||||
for (callee in listOf(rootNode.primaryConstructorImpl, rootNode.boxMethod)) {
|
||||
+irCall(callee).apply {
|
||||
passTypeArgumentsFrom(this@function)
|
||||
for ((index, parameter) in this@function.valueParameters.withIndex()) {
|
||||
putValueArgument(index, irGet(parameter))
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
private fun visitLambda(irBlock: IrBlock): IrExpression {
|
||||
require(irBlock.hasLambdaLikeOrigin() && irBlock.statements.size == 2) { "Illegal lambda: ${irBlock.dump()}" }
|
||||
val (originalFunction, ref) = irBlock.statements
|
||||
require(originalFunction is IrSimpleFunction && ref is IrFunctionReference && ref.symbol.owner == originalFunction) { "Illegal lambda: ${irBlock.dump()}" }
|
||||
val replacement = originalFunction.getReplacement()
|
||||
require(originalFunction == irBlock.statements.first()) { "Illegal lambda: ${irBlock.dump()}" }
|
||||
if (replacement == null) {
|
||||
irBlock.statements[0] = visitFunctionNew(originalFunction)
|
||||
return irBlock
|
||||
}
|
||||
transformFunctionFlat(originalFunction).let { declarations ->
|
||||
require(declarations == listOf(replacement)) {
|
||||
"Expected ${replacement.render()}, got ${declarations?.map { it.render() }}"
|
||||
}
|
||||
}
|
||||
postActionAfterTransformingClassDeclaration(replacement)
|
||||
val newBlock = makeNewLambda(originalFunction, ref)
|
||||
val newFunction = newBlock.statements[0] as IrFunction
|
||||
replacement.origin = IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA
|
||||
when (val body = newFunction.body) {
|
||||
is IrBlockBody -> body.statements.add(0, replacement)
|
||||
is IrExpressionBody -> body.expression = context.createJvmIrBuilder(newFunction.symbol).irBlock {
|
||||
+replacement
|
||||
+body.expression
|
||||
}
|
||||
}
|
||||
replacement.patchDeclarationParents(newFunction)
|
||||
return newBlock
|
||||
}
|
||||
|
||||
override fun visitFunctionReference(expression: IrFunctionReference): IrExpression {
|
||||
val originalFunction = expression.symbol.owner
|
||||
if (originalFunction.getReplacement() == null) return super.visitFunctionReference(expression)
|
||||
return makeNewLambda(originalFunction, expression)
|
||||
}
|
||||
|
||||
private fun IrFunction.getReplacement(): IrFunction? =
|
||||
replacements.getReplacementFunction(this) ?: (this as? IrConstructor)?.let { replacements.getReplacementForRegularClassConstructor(it) }
|
||||
|
||||
private fun makeNewLambda(originalFunction: IrFunction, expression: IrFunctionReference): IrContainerExpression {
|
||||
val currentDeclarationParent = currentDeclarationParent!!
|
||||
val wrapper = context.irFactory.buildFun {
|
||||
updateFrom(originalFunction)
|
||||
modality = Modality.FINAL
|
||||
isFakeOverride = false
|
||||
returnType = originalFunction.returnType
|
||||
name = originalFunction.name
|
||||
visibility = DescriptorVisibilities.LOCAL
|
||||
}.apply newFunction@{
|
||||
parent = currentDeclarationParent
|
||||
assert(typeParameters.isEmpty())
|
||||
copyTypeParametersFrom(originalFunction)
|
||||
val substitutionMap = makeTypeParameterSubstitutionMap(originalFunction, this)
|
||||
require(originalFunction.dispatchReceiverParameter == null || originalFunction.extensionReceiverParameter == null) {
|
||||
"${originalFunction.render()} has both a member and an extension receivers at the same time.\nReferences to such elements are not allowed"
|
||||
}
|
||||
extensionReceiverParameter = (originalFunction.dispatchReceiverParameter ?: originalFunction.extensionReceiverParameter)
|
||||
?.let { it.copyTo(this, type = it.type.substitute(substitutionMap)) }
|
||||
valueParameters = originalFunction.valueParameters.mapIndexed { index, param ->
|
||||
param.copyTo(this, index = index, type = param.type.substitute(substitutionMap))
|
||||
}
|
||||
withinScope(this) {
|
||||
body = with(context.createJvmIrBuilder(symbol)) {
|
||||
irExprBody(irCall(originalFunction).apply {
|
||||
passTypeArgumentsFrom(this@newFunction)
|
||||
for ((newParam, originalParam) in explicitParameters zip originalFunction.explicitParameters) {
|
||||
putArgument(originalParam, irGet(newParam))
|
||||
}
|
||||
}).transform(this@JvmMultiFieldValueClassLowering, null)
|
||||
}
|
||||
postActionAfterTransformingClassDeclaration(this)
|
||||
}
|
||||
}
|
||||
|
||||
val newReference = IrFunctionReferenceImpl(
|
||||
startOffset = UNDEFINED_OFFSET,
|
||||
endOffset = UNDEFINED_OFFSET,
|
||||
type = expression.type,
|
||||
symbol = wrapper.symbol,
|
||||
typeArgumentsCount = expression.typeArgumentsCount,
|
||||
valueArgumentsCount = expression.valueArgumentsCount,
|
||||
reflectionTarget = expression.reflectionTarget,
|
||||
origin = expression.origin,
|
||||
).apply {
|
||||
copyTypeArgumentsFrom(expression)
|
||||
extensionReceiver = (expression.dispatchReceiver ?: expression.extensionReceiver)
|
||||
?.transform(this@JvmMultiFieldValueClassLowering, null)
|
||||
for ((index, arg) in wrapper.valueParameters.indices zip List(expression.valueArgumentsCount, expression::getValueArgument)) {
|
||||
putValueArgument(index, arg?.transform(this@JvmMultiFieldValueClassLowering, null))
|
||||
}
|
||||
copyAttributes(expression)
|
||||
context.getLocalClassType(expression.attributeOwnerId)?.let { context.putLocalClassType(this, it) }
|
||||
}
|
||||
return context.createJvmIrBuilder(getCurrentScopeSymbol(), expression).irBlock(origin = IrStatementOrigin.LAMBDA) {
|
||||
+wrapper
|
||||
+newReference
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitFunctionAccess(expression: IrFunctionAccessExpression): IrExpression {
|
||||
@@ -916,7 +960,7 @@ internal class JvmMultiFieldValueClassLowering(
|
||||
passTypeArgumentsWithOffsets(replacement, originalFunction) { original.getTypeArgument(it)!! }
|
||||
for ((parameter, argument) in replacement.explicitParameters zip newArguments) {
|
||||
if (argument == null) continue
|
||||
putArgument(replacement, parameter, argument.transform(this@JvmMultiFieldValueClassLowering, null))
|
||||
putArgument(replacement, parameter, argument)
|
||||
}
|
||||
}
|
||||
+resultExpression
|
||||
|
||||
+10
-21
@@ -19,19 +19,16 @@ import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.util.collectionUtils.filterIsInstanceAnd
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
internal abstract class JvmValueClassAbstractLowering(
|
||||
val context: JvmBackendContext,
|
||||
protected val fileClassNewDeclarations: MutableMap<IrFile, MutableList<IrSimpleFunction>>,
|
||||
override val scopeStack: MutableList<ScopeWithIr>,
|
||||
) : FileLoweringPass, IrElementTransformerVoidWithContext() {
|
||||
abstract val replacements: MemoizedValueClassAbstractReplacements
|
||||
|
||||
final override fun lower(irFile: IrFile) = withinScope(irFile) {
|
||||
irFile.transformChildrenVoid()
|
||||
addDeclarations(context, fileClassNewDeclarations, irFile)
|
||||
}
|
||||
|
||||
abstract fun IrClass.isSpecificLoweringLogicApplicable(): Boolean
|
||||
@@ -150,14 +147,19 @@ internal abstract class JvmValueClassAbstractLowering(
|
||||
|
||||
internal fun visitStatementContainer(container: IrStatementContainer) {
|
||||
container.statements.transformFlat { statement ->
|
||||
if (statement is IrFunction)
|
||||
transformFunctionFlat(statement)
|
||||
else
|
||||
listOf(statement.transformStatement(this))
|
||||
val newStatements =
|
||||
if (statement is IrFunction) withinScope(statement) { transformFunctionFlat(statement) }
|
||||
else listOf(statement.transformStatement(this))
|
||||
for (replacingDeclaration in (newStatements ?: listOf(statement)).filterIsInstance<IrDeclaration>()) {
|
||||
postActionAfterTransformingClassDeclaration(replacingDeclaration)
|
||||
}
|
||||
newStatements
|
||||
}
|
||||
}
|
||||
|
||||
final override fun visitContainerExpression(expression: IrContainerExpression): IrExpression {
|
||||
protected open fun postActionAfterTransformingClassDeclaration(replacingDeclaration: IrDeclaration) = Unit
|
||||
|
||||
override fun visitContainerExpression(expression: IrContainerExpression): IrExpression {
|
||||
visitStatementContainer(expression)
|
||||
return expression
|
||||
}
|
||||
@@ -379,19 +381,6 @@ internal abstract class JvmValueClassAbstractLowering(
|
||||
final override fun visitErrorExpression(expression: IrErrorExpression) = super.visitErrorExpression(expression)
|
||||
final override fun visitErrorCallExpression(expression: IrErrorCallExpression) = super.visitErrorCallExpression(expression)
|
||||
|
||||
companion object {
|
||||
internal fun addDeclarations(
|
||||
context: JvmBackendContext, fileClassNewDeclarations: MutableMap<IrFile, MutableList<IrSimpleFunction>>, irFile: IrFile
|
||||
) {
|
||||
fileClassNewDeclarations[irFile]?.let { newDeclarations ->
|
||||
val oldFileClass = irFile.declarations.filterIsInstanceAnd<IrClass> { it.isFileClass }.singleOrNull()
|
||||
val allFileDeclarations = (oldFileClass?.declarations ?: listOf()) + newDeclarations
|
||||
val newClass = createFileClass(context, irFile, allFileDeclarations)
|
||||
oldFileClass?.let { irFile.declarations.remove(it) }
|
||||
irFile.addChild(newClass)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract val IrType.needsHandling: Boolean
|
||||
}
|
||||
|
||||
+16
-10
@@ -13,7 +13,10 @@ import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
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.expressions.*
|
||||
import org.jetbrains.kotlin.ir.transformStatement
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||
@@ -29,19 +32,14 @@ val jvmValueClassPhase = makeIrFilePhase(
|
||||
prerequisite = setOf(forLoopsPhase, jvmBuiltInsPhase, collectionStubMethodLowering, singleAbstractMethodPhase),
|
||||
)
|
||||
|
||||
internal class JvmValueClassLoweringDispatcher(
|
||||
private val context: JvmBackendContext,
|
||||
private val fileClassNewDeclarations: MutableMap<IrFile, MutableList<IrSimpleFunction>> = mutableMapOf(),
|
||||
override val scopeStack: MutableList<ScopeWithIr> = mutableListOf(),
|
||||
private val inlineClassLowering: JvmInlineClassLowering = JvmInlineClassLowering(context, fileClassNewDeclarations, scopeStack),
|
||||
private val multiFieldValueClassLowering: JvmMultiFieldValueClassLowering =
|
||||
JvmMultiFieldValueClassLowering(context, fileClassNewDeclarations, scopeStack),
|
||||
) : IrElementTransformerVoidWithContext(), FileLoweringPass {
|
||||
internal class JvmValueClassLoweringDispatcher(context: JvmBackendContext) : IrElementTransformerVoidWithContext(), FileLoweringPass {
|
||||
override val scopeStack: MutableList<ScopeWithIr> = mutableListOf()
|
||||
private val inlineClassLowering: JvmInlineClassLowering = JvmInlineClassLowering(context, scopeStack)
|
||||
private val multiFieldValueClassLowering: JvmMultiFieldValueClassLowering = JvmMultiFieldValueClassLowering(context, scopeStack)
|
||||
|
||||
|
||||
override fun lower(irFile: IrFile) = withinScope(irFile) {
|
||||
irFile.transformChildrenVoid()
|
||||
JvmValueClassAbstractLowering.addDeclarations(context, fileClassNewDeclarations, irFile)
|
||||
}
|
||||
|
||||
|
||||
@@ -106,6 +104,14 @@ internal class JvmValueClassLoweringDispatcher(
|
||||
|
||||
override fun visitReturn(expression: IrReturn, data: Nothing?): Boolean =
|
||||
lowering.needsToVisitReturn(expression) || super.visitReturn(expression, data)
|
||||
|
||||
override fun visitContainerExpression(expression: IrContainerExpression, data: Nothing?): Boolean =
|
||||
visitStatementContainer(expression)
|
||||
|
||||
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()) {
|
||||
|
||||
+8
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.backend.jvm.ir.findSuperDeclaration
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.getSingleAbstractMethod
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.isCompiledToJvmDefault
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.findInterfaceImplementation
|
||||
import org.jetbrains.kotlin.backend.jvm.needsMfvcFlattening
|
||||
import org.jetbrains.kotlin.builtins.functions.BuiltInFunctionArity
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
@@ -598,6 +599,13 @@ internal class LambdaMetafactoryArgumentsBuilder(
|
||||
}
|
||||
}
|
||||
|
||||
// ** Value classes **
|
||||
// All Kotlin inline classes are final,
|
||||
// and their supertypes are trivially mapped to reference types.
|
||||
if (adapteeType.needsMfvcFlattening()) {
|
||||
return TypeAdaptationConstraint.CONFLICT
|
||||
}
|
||||
|
||||
// Other cases don't enforce type adaptation
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@ import org.jetbrains.kotlin.backend.common.Mapping
|
||||
import org.jetbrains.kotlin.backend.common.ir.Ir
|
||||
import org.jetbrains.kotlin.backend.common.lower.LocalDeclarationsLowering
|
||||
import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
|
||||
import org.jetbrains.kotlin.backend.jvm.MemoizedMultiFieldValueClassReplacements.RemappedParameter.MultiFieldValueClassMapping
|
||||
import org.jetbrains.kotlin.backend.jvm.MemoizedMultiFieldValueClassReplacements.RemappedParameter.RegularMapping
|
||||
import org.jetbrains.kotlin.backend.jvm.caches.BridgeLoweringCache
|
||||
import org.jetbrains.kotlin.backend.jvm.caches.CollectionStubComputer
|
||||
import org.jetbrains.kotlin.backend.jvm.mapping.IrTypeMapper
|
||||
@@ -32,7 +34,7 @@ import org.jetbrains.kotlin.ir.symbols.*
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.IrTypeSystemContext
|
||||
import org.jetbrains.kotlin.ir.types.defaultType
|
||||
import org.jetbrains.kotlin.ir.util.SymbolTable
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
@@ -267,4 +269,34 @@ class JvmBackendContext(
|
||||
|
||||
override fun shouldGenerateHandlerParameterForDefaultBodyFun() = true
|
||||
}
|
||||
|
||||
override fun remapMultiFieldValueClassStructure(
|
||||
oldFunction: IrFunction,
|
||||
newFunction: IrFunction,
|
||||
parametersMappingOrNull: Map<IrValueParameter, IrValueParameter>?
|
||||
) {
|
||||
val parametersMapping = parametersMappingOrNull ?: run {
|
||||
require(oldFunction.explicitParametersCount == newFunction.explicitParametersCount) {
|
||||
"Use non-default mapping instead:\n${oldFunction.render()}\n${newFunction.render()}"
|
||||
}
|
||||
oldFunction.explicitParameters.zip(newFunction.explicitParameters).toMap()
|
||||
}
|
||||
val oldRemappedParameters = multiFieldValueClassReplacements.bindingNewFunctionToParameterTemplateStructure[oldFunction] ?: return
|
||||
val newRemapsFromOld = oldRemappedParameters.mapNotNull { oldRemapping ->
|
||||
when (oldRemapping) {
|
||||
is RegularMapping -> parametersMapping[oldRemapping.valueParameter]?.let(::RegularMapping)
|
||||
is MultiFieldValueClassMapping -> {
|
||||
val newParameters = oldRemapping.valueParameters.map { parametersMapping[it] }
|
||||
when {
|
||||
newParameters.all { it == null } -> null
|
||||
newParameters.none { it == null } -> oldRemapping.copy(valueParameters = newParameters.map { it!! })
|
||||
else -> error("Illegal new parameters:\n${newParameters.joinToString("\n") { it?.dump() ?: "null" }}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
val remappedParameters = newRemapsFromOld.flatMap { remap -> remap.valueParameters.map { it to remap } }.toMap()
|
||||
val newBinding = newFunction.explicitParameters.map { remappedParameters[it] ?: RegularMapping(it) }.distinct()
|
||||
multiFieldValueClassReplacements.bindingNewFunctionToParameterTemplateStructure[newFunction] = newBinding
|
||||
}
|
||||
}
|
||||
|
||||
+2
-10
@@ -172,11 +172,7 @@ class MemoizedInlineClassReplacements(
|
||||
it.defaultValue = parameter.defaultValue?.patchDeclarationParents(this)
|
||||
}
|
||||
}
|
||||
context.multiFieldValueClassReplacements.run {
|
||||
bindingNewFunctionToParameterTemplateStructure[function]?.also {
|
||||
bindingNewFunctionToParameterTemplateStructure[this@buildReplacement] = it
|
||||
}
|
||||
}
|
||||
context.remapMultiFieldValueClassStructure(function, this, parametersMappingOrNull = null)
|
||||
}
|
||||
|
||||
override fun createStaticReplacement(function: IrFunction): IrSimpleFunction =
|
||||
@@ -212,11 +208,7 @@ class MemoizedInlineClassReplacements(
|
||||
}
|
||||
}
|
||||
valueParameters = newValueParameters
|
||||
context.multiFieldValueClassReplacements.run {
|
||||
bindingNewFunctionToParameterTemplateStructure[function]?.also {
|
||||
bindingNewFunctionToParameterTemplateStructure[this@buildReplacement] = it
|
||||
}
|
||||
}
|
||||
context.remapMultiFieldValueClassStructure(function, this, parametersMappingOrNull = null)
|
||||
}
|
||||
|
||||
private fun buildReplacement(
|
||||
|
||||
+4
-3
@@ -101,7 +101,9 @@ class MemoizedMultiFieldValueClassReplacements(
|
||||
|
||||
else -> replacementOrigin
|
||||
}
|
||||
name = InlineClassAbi.mangledNameFor(function, mangleReturnTypes = false, useOldMangleRules = false)
|
||||
name =
|
||||
if (function.isLocal && (function !is IrSimpleFunction || function.overriddenSymbols.isEmpty())) function.name
|
||||
else InlineClassAbi.mangledNameFor(function, mangleReturnTypes = false, useOldMangleRules = false)
|
||||
}
|
||||
|
||||
private fun makeAndAddGroupedValueParametersFrom(
|
||||
@@ -226,8 +228,7 @@ class MemoizedMultiFieldValueClassReplacements(
|
||||
override val getReplacementFunctionImpl: (IrFunction) -> IrSimpleFunction? =
|
||||
storageManager.createMemoizedFunctionWithNullableValues { function ->
|
||||
when {
|
||||
(function.isLocal && function is IrSimpleFunction && function.overriddenSymbols.isEmpty()) ||
|
||||
(function.origin == IrDeclarationOrigin.DELEGATED_PROPERTY_ACCESSOR && function.visibility == DescriptorVisibilities.LOCAL) ||
|
||||
(function.origin == IrDeclarationOrigin.DELEGATED_PROPERTY_ACCESSOR && function.visibility == DescriptorVisibilities.LOCAL) ||
|
||||
function.isStaticValueClassReplacement ||
|
||||
function.origin == IrDeclarationOrigin.GENERATED_MULTI_FIELD_VALUE_CLASS_MEMBER && function.isAccessor ||
|
||||
function.origin == JvmLoweredDeclarationOrigin.MULTI_FIELD_VALUE_CLASS_GENERATED_IMPL_METHOD ||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
@kotlin.Metadata
|
||||
public final class ClassFlatteningKt {
|
||||
// source: 'classFlattening.kt'
|
||||
private final static method box$lambda$3$lambda$2(p0: int, p1: int, p2: java.lang.String, p3: int, p4: int, p5: java.lang.String, p6: int, p7: int, p8: java.lang.String): void
|
||||
public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String
|
||||
public final static method gmfvc-Ket90g4(p0: int, p1: int, p2: int, @org.jetbrains.annotations.NotNull p3: java.lang.String, p4: int, p5: int, p6: int, @org.jetbrains.annotations.NotNull p7: java.lang.String, p8: int): int
|
||||
public final static method ic-K5cTq2M(p0: int): int
|
||||
|
||||
+1968
-97
File diff suppressed because it is too large
Load Diff
@@ -1,14 +1,62 @@
|
||||
// CHECK_BYTECODE_LISTING
|
||||
// WITH_STDLIB
|
||||
// WITH_COROUTINES
|
||||
// TARGET_BACKEND: JVM_IR
|
||||
// WORKS_WHEN_VALUE_CLASS
|
||||
// LANGUAGE: +ValueClasses
|
||||
// LAMBDAS: INDY
|
||||
// ^ to ensure that LAMBDAS are actually CLASSes
|
||||
|
||||
// FILE: caller.kt
|
||||
import kotlin.coroutines.*
|
||||
|
||||
fun runSuspend(block: suspend () -> Unit) {
|
||||
val run = RunSuspend()
|
||||
block.startCoroutine(run)
|
||||
run.await()
|
||||
}
|
||||
|
||||
private class RunSuspend : Continuation<Unit> {
|
||||
override val context: CoroutineContext
|
||||
get() = EmptyCoroutineContext
|
||||
|
||||
var result: Result<Unit>? = null
|
||||
|
||||
override fun resumeWith(result: Result<Unit>) = synchronized(this) {
|
||||
this.result = result
|
||||
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") (this as Object).notifyAll()
|
||||
}
|
||||
|
||||
fun await() = synchronized(this) {
|
||||
while (true) {
|
||||
when (val result = this.result) {
|
||||
null -> @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") (this as Object).wait()
|
||||
else -> {
|
||||
result.getOrThrow() // throw up failure
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: test.kt
|
||||
|
||||
@JvmInline
|
||||
value class DPoint(val x: Double, val y: Double) {
|
||||
fun f(z: Double) = x + y + z
|
||||
suspend fun suspended() = this
|
||||
inline suspend fun suspendedInline() = this
|
||||
|
||||
fun functionWithInlineClass(other: DPoint, n: UInt) = x.toUInt() + y.toUInt() + other.x.toUInt() + other.y.toUInt() + n
|
||||
|
||||
suspend fun suspendFunctionWithLambda(other: DPoint, f: suspend (DPoint) -> DPoint) = DPoint(f(this).x, f(other).y).suspendedInline()
|
||||
|
||||
suspend fun suspendInlineFunctionWithLambda(other: DPoint, f: suspend (DPoint) -> DPoint) = DPoint(f(this).x, f(other).y).suspendedInline()
|
||||
}
|
||||
|
||||
fun DPoint.extensionFunction(z: Double) = x + y + z
|
||||
|
||||
fun g(point: DPoint, z: Double) = point.f(z)
|
||||
|
||||
class A(val point: DPoint) {
|
||||
@@ -25,31 +73,144 @@ fun makeDPoint(x: Double, y: Double, maker: (Double, Double) -> DPoint) = maker(
|
||||
|
||||
inline fun makeDPointInline(x: Double, y: Double, maker: (Double, Double) -> DPoint) = maker(x, y)
|
||||
|
||||
inline fun <T> id(x: T) = x
|
||||
|
||||
fun box(): String {
|
||||
val dPoint = DPoint(1.0, 2.0)
|
||||
val a = A(dPoint)
|
||||
|
||||
|
||||
require((::DPoint)(1.0, 2.0) == dPoint)
|
||||
require((dPoint::f)(3.0) == 6.0)
|
||||
require((DPoint::f)(dPoint, 3.0) == 6.0)
|
||||
require((dPoint::extensionFunction)(3.0) == 6.0)
|
||||
require((DPoint::extensionFunction)(dPoint, 3.0) == 6.0)
|
||||
|
||||
runSuspend { require(dPoint.suspended() == dPoint) }
|
||||
runSuspend { require((dPoint::suspended)() == dPoint) }
|
||||
runSuspend { require((DPoint::suspended)(dPoint) == dPoint) }
|
||||
runSuspend { require(dPoint.suspendedInline() == dPoint) }
|
||||
runSuspend { require((dPoint::suspendedInline)() == dPoint) }
|
||||
runSuspend { require((DPoint::suspendedInline)(dPoint) == dPoint) }
|
||||
|
||||
runSuspend { require(dPoint.suspendFunctionWithLambda(dPoint, DPoint::suspended) == dPoint) }
|
||||
runSuspend { require((dPoint::suspendFunctionWithLambda)(dPoint, DPoint::suspended) == dPoint) }
|
||||
runSuspend { require((DPoint::suspendFunctionWithLambda)(dPoint, dPoint, DPoint::suspended) == dPoint) }
|
||||
runSuspend { require(dPoint.suspendFunctionWithLambda(dPoint, DPoint::suspendedInline) == dPoint) }
|
||||
runSuspend { require((dPoint::suspendFunctionWithLambda)(dPoint, DPoint::suspendedInline) == dPoint) }
|
||||
runSuspend { require((DPoint::suspendFunctionWithLambda)(dPoint, dPoint, DPoint::suspendedInline) == dPoint) }
|
||||
runSuspend { require(dPoint.suspendFunctionWithLambda(dPoint) { it.suspended() } == dPoint) }
|
||||
runSuspend { require((dPoint::suspendFunctionWithLambda)(dPoint) { it.suspended() } == dPoint) }
|
||||
runSuspend { require((DPoint::suspendFunctionWithLambda)(dPoint, dPoint) { it.suspended() } == dPoint) }
|
||||
runSuspend { require(dPoint.suspendFunctionWithLambda(dPoint) { it.suspendedInline() } == dPoint) }
|
||||
runSuspend { require((dPoint::suspendFunctionWithLambda)(dPoint) { it.suspendedInline() } == dPoint) }
|
||||
runSuspend { require((DPoint::suspendFunctionWithLambda)(dPoint, dPoint) { it.suspendedInline() } == dPoint) }
|
||||
|
||||
runSuspend { require(dPoint.suspendInlineFunctionWithLambda(dPoint, DPoint::suspended) == dPoint) }
|
||||
runSuspend { require((dPoint::suspendInlineFunctionWithLambda)(dPoint, DPoint::suspended) == dPoint) }
|
||||
runSuspend { require((DPoint::suspendInlineFunctionWithLambda)(dPoint, dPoint, DPoint::suspended) == dPoint) }
|
||||
runSuspend { require(dPoint.suspendInlineFunctionWithLambda(dPoint, DPoint::suspendedInline) == dPoint) }
|
||||
runSuspend { require((dPoint::suspendInlineFunctionWithLambda)(dPoint, DPoint::suspendedInline) == dPoint) }
|
||||
runSuspend { require((DPoint::suspendInlineFunctionWithLambda)(dPoint, dPoint, DPoint::suspendedInline) == dPoint) }
|
||||
runSuspend { require(dPoint.suspendInlineFunctionWithLambda(dPoint) { it.suspended() } == dPoint) }
|
||||
runSuspend { require((dPoint::suspendInlineFunctionWithLambda)(dPoint) { it.suspended() } == dPoint) }
|
||||
runSuspend { require((DPoint::suspendInlineFunctionWithLambda)(dPoint, dPoint) { it.suspended() } == dPoint) }
|
||||
runSuspend { require(dPoint.suspendInlineFunctionWithLambda(dPoint) { it.suspendedInline() } == dPoint) }
|
||||
runSuspend { require((dPoint::suspendInlineFunctionWithLambda)(dPoint) { it.suspendedInline() } == dPoint) }
|
||||
runSuspend { require((DPoint::suspendInlineFunctionWithLambda)(dPoint, dPoint) { it.suspendedInline() } == dPoint) }
|
||||
|
||||
require((dPoint::functionWithInlineClass)(dPoint, 100U) == 106U)
|
||||
require((DPoint::functionWithInlineClass)(dPoint, dPoint, 100U) == 106U)
|
||||
|
||||
require((::g)(dPoint, 3.0) == 6.0)
|
||||
require((a::f)(dPoint, 3.0) == 36.0)
|
||||
|
||||
require((A::f)(a, dPoint, 3.0) == 36.0)
|
||||
|
||||
require((::DPoint)(1.0, DPoint(1.0, 2.0).y) == dPoint)
|
||||
require((dPoint::f)(DPoint(1.0, 3.0).y) == 6.0)
|
||||
require((DPoint::f)(dPoint, DPoint(1.0, 3.0).y) == 6.0)
|
||||
require((::g)(dPoint, DPoint(1.0, 3.0).y) == 6.0)
|
||||
require((a::f)(dPoint, DPoint(1.0, 3.0).y) == 36.0)
|
||||
|
||||
require((A::f)(a, dPoint, DPoint(1.0, 3.0).y) == 36.0)
|
||||
|
||||
require(consume(DPoint(1.0, 2.0), DPoint(3.0, 4.0), DPoint::plus) == DPoint(4.0, 6.0))
|
||||
require(consume(DPoint(1.0, 2.0), DPoint(3.0, 4.0)) { dPoint, other -> dPoint.plus(other) } == DPoint(4.0, 6.0))
|
||||
require(consumeInline(DPoint(1.0, 2.0), DPoint(3.0, 4.0), DPoint::plus) == DPoint(4.0, 6.0))
|
||||
|
||||
require(consumeInline(DPoint(1.0, 2.0), DPoint(3.0, 4.0)) { dPoint, other -> dPoint.plus(other) } == DPoint(4.0, 6.0))
|
||||
require(
|
||||
consume(DPoint(1.0, 2.0), DPoint(3.0, 4.0), fun(dPoint: DPoint, other: DPoint): DPoint = dPoint.plus(other)) ==
|
||||
DPoint(4.0, 6.0)
|
||||
)
|
||||
require(
|
||||
consumeInline(DPoint(1.0, 2.0), DPoint(3.0, 4.0), fun(dPoint: DPoint, other: DPoint): DPoint = dPoint.plus(other)) ==
|
||||
DPoint(4.0, 6.0)
|
||||
)
|
||||
|
||||
require(makeDPoint(1.0, 2.0, ::DPoint) == DPoint(1.0, 2.0))
|
||||
require(makeDPointInline(1.0, 2.0, ::DPoint) == DPoint(1.0, 2.0))
|
||||
|
||||
|
||||
require(::DPoint == ::DPoint)
|
||||
require(::DPoint == any1())
|
||||
require(dPoint::f == dPoint::f)
|
||||
require(DPoint::f == DPoint::f)
|
||||
require(dPoint::f == any2(dPoint))
|
||||
require(DPoint::f == any2())
|
||||
require(dPoint::suspended == dPoint::suspended)
|
||||
require(DPoint::suspended == DPoint::suspended)
|
||||
require(dPoint::suspended == any3(dPoint))
|
||||
require(DPoint::suspended == any3())
|
||||
require(dPoint::suspendedInline == dPoint::suspendedInline)
|
||||
require(DPoint::suspendedInline == DPoint::suspendedInline)
|
||||
require(dPoint::suspendedInline == any4(dPoint))
|
||||
require(DPoint::suspendedInline == any4())
|
||||
require(dPoint::functionWithInlineClass == dPoint::functionWithInlineClass)
|
||||
require(DPoint::functionWithInlineClass == DPoint::functionWithInlineClass)
|
||||
require(dPoint::functionWithInlineClass == any5(dPoint))
|
||||
require(DPoint::functionWithInlineClass == any5())
|
||||
require(dPoint::extensionFunction == dPoint::extensionFunction)
|
||||
require(DPoint::extensionFunction == DPoint::extensionFunction)
|
||||
require(dPoint::extensionFunction == any6(dPoint))
|
||||
require(DPoint::extensionFunction == any6())
|
||||
require(dPoint::suspendFunctionWithLambda == dPoint::suspendFunctionWithLambda)
|
||||
require(DPoint::suspendFunctionWithLambda == DPoint::suspendFunctionWithLambda)
|
||||
require(dPoint::suspendFunctionWithLambda == any7(dPoint))
|
||||
require(DPoint::suspendFunctionWithLambda == any7())
|
||||
require(dPoint::suspendInlineFunctionWithLambda == dPoint::suspendInlineFunctionWithLambda)
|
||||
require(DPoint::suspendInlineFunctionWithLambda == DPoint::suspendInlineFunctionWithLambda)
|
||||
require(dPoint::suspendInlineFunctionWithLambda == any8(dPoint))
|
||||
require(DPoint::suspendInlineFunctionWithLambda == any8())
|
||||
require(::g == ::g)
|
||||
require(a::f == a::f)
|
||||
require(A::f == A::f)
|
||||
require(DPoint::plus == DPoint::plus)
|
||||
require(dPoint.let { DPoint(it.x * 2, it.y * 2) } == DPoint(2.0, 4.0))
|
||||
require(dPoint.let(::id) == DPoint(1.0, 2.0))
|
||||
|
||||
runSuspend { require(requiresF(dPoint) { it } == dPoint) }
|
||||
runSuspend { require(requiresF(dPoint, F { it }) == dPoint) }
|
||||
|
||||
return "OK"
|
||||
}
|
||||
|
||||
// FILE: another.kt
|
||||
|
||||
fun any1(): Any = ::DPoint
|
||||
fun any2(dPoint: DPoint): Any = dPoint::f
|
||||
fun any2(): Any = DPoint::f
|
||||
fun any3(dPoint: DPoint): Any = dPoint::suspended
|
||||
fun any3(): Any = DPoint::suspended
|
||||
fun any4(dPoint: DPoint): Any = dPoint::suspendedInline
|
||||
fun any4(): Any = DPoint::suspendedInline
|
||||
fun any5(dPoint: DPoint): Any = dPoint::functionWithInlineClass
|
||||
fun any5(): Any = DPoint::functionWithInlineClass
|
||||
fun any6(dPoint: DPoint): Any = dPoint::extensionFunction
|
||||
fun any6(): Any = DPoint::extensionFunction
|
||||
fun any7(dPoint: DPoint): Any = dPoint::suspendFunctionWithLambda
|
||||
fun any7(): Any = DPoint::suspendFunctionWithLambda
|
||||
fun any8(dPoint: DPoint): Any = dPoint::suspendInlineFunctionWithLambda
|
||||
fun any8(): Any = DPoint::suspendInlineFunctionWithLambda
|
||||
|
||||
fun interface F {
|
||||
suspend fun run(dPoint: DPoint): DPoint
|
||||
}
|
||||
|
||||
suspend fun requiresF(x: DPoint, f: F) = f.run(x)
|
||||
+1968
-97
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user