[IR] Support MFVC-typed properties and interfaces delegates

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

#KT-1179
This commit is contained in:
Evgeniy.Zhelenskiy
2022-10-23 05:40:53 +02:00
committed by Space Team
parent 4d426fc4cd
commit 38c80192f9
15 changed files with 690 additions and 64 deletions
@@ -26,10 +26,7 @@ import org.jetbrains.kotlin.fir.languageVersionSettings
import org.jetbrains.kotlin.fir.packageFqName
import org.jetbrains.kotlin.fir.resolve.fqName
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.fir.types.coneTypeSafe
import org.jetbrains.kotlin.fir.types.customAnnotations
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.StandardClassIds
@@ -55,6 +52,16 @@ object FirAnnotationChecker : FirBasicDeclarationChecker() {
checkAnnotationTarget(declaration, annotation, context, reporter)
}
if (declaration is FirCallableDeclaration) {
val receiverParameter = declaration.receiverParameter
if (receiverParameter != null) {
for (receiverAnnotation in receiverParameter.annotations) {
reportIfMfvc(context, reporter, receiverAnnotation, "receivers", receiverParameter.typeRef)
}
}
}
if (deprecatedSinceKotlin != null) {
checkDeprecatedCalls(deprecatedSinceKotlin, deprecated, context, reporter)
}
@@ -72,19 +79,26 @@ object FirAnnotationChecker : FirBasicDeclarationChecker() {
}
}
private fun reportIfMfvc(context: CheckerContext, reporter: DiagnosticReporter, annotation: FirAnnotation, hint: String, type: FirTypeRef) {
if (type.needsMultiFieldValueClassFlattening(context.session)) {
reporter.reportOn(annotation.source, FirErrors.ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET, hint, context)
}
}
private fun checkMultiFieldValueClassAnnotationRestrictions(
declaration: FirDeclaration,
annotation: FirAnnotation,
context: CheckerContext,
reporter: DiagnosticReporter
) {
fun FirPropertyAccessor.hasNoReceivers() = contextReceivers.isEmpty() && receiverParameter?.typeRef == null &&
propertySymbol.resolvedReceiverTypeRef == null && propertySymbol.resolvedContextReceivers.isEmpty()
val (hint, type) = when (annotation.useSiteTarget) {
FIELD, PROPERTY_DELEGATE_FIELD -> "fields" to ((declaration as? FirProperty)?.backingField?.returnTypeRef ?: return)
FILE, PROPERTY, PROPERTY_SETTER -> return
PROPERTY_GETTER -> "getters" to ((declaration as? FirPropertyAccessor)?.returnTypeRef ?: return)
RECEIVER -> "receivers" to ((declaration as? FirCallableDeclaration)?.receiverTypeRef ?: return)
CONSTRUCTOR_PARAMETER, SETTER_PARAMETER -> "parameters" to (declaration as? FirValueParameter ?: return).returnTypeRef
null -> when {
FIELD -> "fields" to ((declaration as? FirProperty)?.backingField?.returnTypeRef ?: return)
PROPERTY_DELEGATE_FIELD -> "delegate fields" to ((declaration as? FirProperty)?.delegate?.typeRef ?: return)
RECEIVER -> "receivers" to ((declaration as? FirCallableDeclaration)?.receiverParameter?.typeRef ?: return)
FILE, PROPERTY, PROPERTY_GETTER, PROPERTY_SETTER, CONSTRUCTOR_PARAMETER, SETTER_PARAMETER, null -> when {
declaration is FirProperty && !declaration.isLocal -> {
val allowedAnnotationTargets = annotation.getAllowedAnnotationTargets(context.session)
when {
@@ -97,17 +111,13 @@ object FirAnnotationChecker : FirBasicDeclarationChecker() {
declaration is FirField -> "fields" to declaration.returnTypeRef
declaration is FirValueParameter -> "parameters" to declaration.returnTypeRef
declaration is FirVariable -> "variables" to declaration.returnTypeRef
declaration is FirPropertyAccessor && declaration.isGetter &&
declaration.receiverTypeRef == null &&
declaration.contextReceivers.isEmpty() ->
declaration is FirPropertyAccessor && declaration.isGetter && declaration.hasNoReceivers() ->
"getters" to declaration.returnTypeRef
else -> return
}
}
if (type.needsMfvcFlattening(context.session)) {
reporter.reportOn(annotation.source, FirErrors.ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET, hint, context)
}
reportIfMfvc(context, reporter, annotation, hint, type)
}
private fun checkAnnotationTarget(
@@ -50447,6 +50447,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/valueClasses/defaultParameters.kt", TransformersFunctions.getReplaceOptionalJvmInlineAnnotationWithReal());
}
@Test
@TestMetadata("delegating.kt")
public void testDelegating() throws Exception {
runTest("compiler/testData/codegen/box/valueClasses/delegating.kt", TransformersFunctions.getReplaceOptionalJvmInlineAnnotationWithReal());
}
@Test
@TestMetadata("equality.kt")
public void testEquality() throws Exception {
@@ -138,9 +138,9 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
get() = this.symbol.owner
fun IrBlockBuilder.addReplacement(expression: IrGetField): IrExpression? {
val property = expression.field.property ?: return null
expression.receiver?.get(this, property.name)?.let { +it; return it }
val node = replacements.getMfvcPropertyNode(property) ?: return null
val field = expression.field
expression.receiver?.get(this, field.name)?.let { +it; return it }
val node = replacements.getMfvcFieldNode(field) ?: return null
val typeArguments = makeTypeArgumentsFromField(expression)
val instance: ReceiverBasedMfvcNodeInstance =
node.createInstanceFromBox(this, typeArguments, expression.receiver, AccessType.AlwaysPrivate, ::variablesSaver)
@@ -151,9 +151,9 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
}
fun IrBlockBuilder.addReplacement(expression: IrSetField, safe: Boolean): IrExpression? {
val property = expression.field.property ?: return null
expression.receiver?.get(this, property.name)?.let { +it; return it }
val node = replacements.getMfvcPropertyNode(property) ?: return null
val field = expression.field
expression.receiver?.get(this, field.name)?.let { +it; return it }
val node = replacements.getMfvcFieldNode(field) ?: return null
val typeArguments = makeTypeArgumentsFromField(expression)
val instance: ReceiverBasedMfvcNodeInstance =
node.createInstanceFromBox(this, typeArguments, expression.receiver, AccessType.AlwaysPrivate, ::variablesSaver)
@@ -317,44 +317,62 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
irClass.primaryConstructor?.let {
replacements.getReplacementForRegularClassConstructor(it)?.let { replacement -> addBindingsFor(it, replacement) }
}
val properties = collectPropertiesAfterLowering(irClass)
val oldBackingFields = properties.mapNotNull { property -> property.backingField?.let { property to it } }.toMap()
val propertiesReplacement = collectRegularClassMfvcPropertiesReplacement(properties) // resets backing fields
val propertiesOrFields = collectPropertiesOrFieldsAfterLowering(irClass)
val oldBackingFields = propertiesOrFields.mapNotNull { propertyOrField ->
val property = (propertyOrField as? IrPropertyOrIrField.Property)?.property ?: return@mapNotNull null
property.backingField?.let { property to it }
}.toMap()
val propertiesOrFieldsReplacement = collectRegularClassMfvcPropertiesOrFieldsReplacement(propertiesOrFields) // resets backing fields
val fieldsToRemove = propertiesReplacement.keys.mapNotNull { oldBackingFields[it] }.toSet()
val fieldsToRemove = propertiesOrFieldsReplacement.keys.mapNotNull {
when (it) {
is IrPropertyOrIrField.Field -> it.field
is IrPropertyOrIrField.Property -> oldBackingFields[it.property]
}
}.toSet()
if (fieldsToRemove.isNotEmpty() || propertiesReplacement.isNotEmpty()) {
val newDeclarations = makeNewDeclarationsForRegularClass(fieldsToRemove, propertiesReplacement, irClass)
if (fieldsToRemove.isNotEmpty() || propertiesOrFieldsReplacement.isNotEmpty()) {
val newDeclarations = makeNewDeclarationsForRegularClass(fieldsToRemove, propertiesOrFieldsReplacement, irClass)
irClass.declarations.replaceAll(newDeclarations)
}
}
private fun collectRegularClassMfvcPropertiesReplacement(properties: LinkedHashSet<IrProperty>) =
LinkedHashMap<IrProperty, IntermediateMfvcNode>().apply {
for (property in properties) {
val node = replacements.getRegularClassMfvcPropertyNode(property) ?: continue
put(property, node)
private fun collectRegularClassMfvcPropertiesOrFieldsReplacement(propertiesOrFields: LinkedHashSet<IrPropertyOrIrField>) =
LinkedHashMap<IrPropertyOrIrField, IntermediateMfvcNode>().apply {
for (propertyOrField in propertiesOrFields) {
val node = when (propertyOrField) {
is IrPropertyOrIrField.Field -> replacements.getMfvcFieldNode(propertyOrField.field)
is IrPropertyOrIrField.Property -> replacements.getMfvcPropertyNode(propertyOrField.property)
} ?: continue
put(propertyOrField, node as IntermediateMfvcNode)
}
}
private fun makeNewDeclarationsForRegularClass(
fieldsToRemove: Set<IrField>,
propertiesReplacement: Map<IrProperty, IntermediateMfvcNode>,
propertiesOrFieldsReplacement: Map<IrPropertyOrIrField, IntermediateMfvcNode>,
irClass: IrClass,
) = buildList {
for (element in irClass.declarations) {
when (element) {
!is IrField, !in fieldsToRemove -> add(element)
else -> {
val replacement = propertiesReplacement[element.property!!]!!
addAll(replacement.fields!!)
element.initializer?.let { initializer -> add(makeInitializerReplacement(irClass, element, initializer)) }
val fields = element.property?.let { propertiesOrFieldsReplacement[IrPropertyOrIrField.Property(it)] }?.fields
?: propertiesOrFieldsReplacement[IrPropertyOrIrField.Field(element)]?.fields
if (fields != null) {
addAll(fields)
element.initializer?.let { initializer -> add(makeInitializerReplacement(irClass, element, initializer)) }
} else {
add(element)
}
}
}
}
for (node in propertiesReplacement.values) {
addAll(node.allInnerUnboxMethods.filter { it.parent == irClass })
for ((propertyOrField, node) in propertiesOrFieldsReplacement.entries) {
if (propertyOrField is IrPropertyOrIrField.Property) { // they are not used, only boxes are used for them
addAll(node.allInnerUnboxMethods.filter { it.parent == irClass })
}
}
}
@@ -928,9 +946,12 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
oldArgument == null -> List(parametersCount) { null }
parametersCount == 1 -> listOf(oldArgument.transform(this@JvmMultiFieldValueClassLowering, null))
else -> {
val type = oldArgument.type as IrSimpleType
require(type.needsMfvcFlattening()) { "Unexpected type: ${type.render()}" }
flattenExpression(oldArgument).also {
val castedIfNeeded = when {
oldArgument.type.needsMfvcFlattening() -> oldArgument
oldArgument.type.makeNotNull().needsMfvcFlattening() -> irImplicitCast(oldArgument, oldArgument.type.makeNotNull())
else -> error("Unexpected type: ${oldArgument.type.render()}")
}
flattenExpression(castedIfNeeded).also {
require(it.size == parametersCount) { "Expected $parametersCount arguments but got ${it.size}" }
}
}
@@ -302,10 +302,27 @@ class MemoizedMultiFieldValueClassReplacements(
createIntermediateNodeForMfvcPropertyOfRegularClass(parent, context, property)
}
fun getRegularClassMfvcPropertyNode(property: IrProperty): IntermediateMfvcNode? {
val parent = property.parent
fun getMfvcFieldNode(field: IrField): NameableMfvcNode? {
val parent = field.parent
val property = field.correspondingPropertySymbol?.owner
return when {
property.run { backingField?.type ?: getter?.returnType }?.needsMfvcFlattening() != true -> null
property?.isDelegated == false -> getMfvcPropertyNode(property)
parent !is IrClass -> null
!field.type.needsMfvcFlattening() -> null
else -> getMfvcStandaloneFieldNodeImpl(field)
}
}
private val getMfvcStandaloneFieldNodeImpl: (IrField) -> NameableMfvcNode = storageManager.createMemoizedFunction { field ->
val parent = field.parentAsClass
createIntermediateNodeForStandaloneMfvcField(parent, context, field)
}
private fun getRegularClassMfvcPropertyNode(property: IrProperty): IntermediateMfvcNode? {
val parent = property.parent
val types = listOfNotNull(property.backingField?.takeUnless { property.isDelegated }?.type, property.getter?.returnType)
return when {
types.isEmpty() || types.any { !it.needsMfvcFlattening() } -> null
parent !is IrClass -> null
property.isFakeOverride -> null
property.getter.let { it != null && (it.contextReceiverParametersCount > 0 || it.extensionReceiverParameter != null) } -> null
@@ -122,8 +122,9 @@ class NameableMfvcNodeImpl(
@JvmStatic
fun makeFullFieldName(rootPropertyName: String?, nameParts: List<IndexedNamePart>): Name {
val joined = (listOf(rootPropertyName ?: "field") + nameParts.map { it.index.toString() }).joinToString("-")
return Name.identifier(joined)
val name = Name.guessByFirstCharacter(rootPropertyName ?: "field")
val joined = (listOf(name.asStringStripSpecialMarkers()) + nameParts.map { it.index.toString() }).joinToString("-")
return if (name.isSpecial) Name.special("<$joined>") else Name.identifier(joined)
}
}
}
@@ -8,6 +8,8 @@ package org.jetbrains.kotlin.backend.jvm
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.lower.irBlockBody
import org.jetbrains.kotlin.backend.common.lower.parents
import org.jetbrains.kotlin.backend.jvm.IrPropertyOrIrField.Field
import org.jetbrains.kotlin.backend.jvm.IrPropertyOrIrField.Property
import org.jetbrains.kotlin.backend.jvm.ir.createJvmIrBuilder
import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
import org.jetbrains.kotlin.backend.jvm.ir.upperBound
@@ -191,7 +193,7 @@ fun createIntermediateMfvcNode(
val replacements = context.multiFieldValueClassReplacements
val rootNode = replacements.getRootMfvcNode(valueClass)
val oldField = oldGetter?.correspondingPropertySymbol?.owner?.backingField
val oldField = oldGetter?.correspondingPropertySymbol?.owner?.backingFieldIfNotDelegate
val shadowBackingFieldProperty = if (oldField == null) oldGetter?.getGetterField()?.correspondingPropertySymbol?.owner else null
val useOldGetter = oldGetter != null && (oldField == null || !oldGetter.isDefaultGetter(oldField))
@@ -243,18 +245,29 @@ fun createIntermediateMfvcNode(
)
}
fun collectPropertiesAfterLowering(irClass: IrClass) = LinkedHashSet<IrProperty>().apply {
for (element in irClass.declarations) {
if (element is IrField) {
element.correspondingPropertySymbol?.owner?.let { add(it) }
} else if (element is IrSimpleFunction && element.extensionReceiverParameter == null && element.contextReceiverParametersCount == 0) {
element.correspondingPropertySymbol?.owner?.let { add(it) }
}
}
fun collectPropertiesAfterLowering(irClass: IrClass): LinkedHashSet<IrProperty> =
LinkedHashSet(collectPropertiesOrFieldsAfterLowering(irClass).map { (it as Property).property })
sealed class IrPropertyOrIrField {
data class Property(val property: IrProperty) : IrPropertyOrIrField()
data class Field(val field: IrField) : IrPropertyOrIrField()
}
fun collectPropertiesOrFieldsAfterLowering(irClass: IrClass): LinkedHashSet<IrPropertyOrIrField> =
LinkedHashSet<IrPropertyOrIrField>().apply {
for (element in irClass.declarations) {
if (element is IrField) {
element.correspondingPropertySymbol?.owner?.takeUnless { it.isDelegated }?.let { add(Property(it)) } ?: add(Field(element))
} else if (element is IrSimpleFunction && element.extensionReceiverParameter == null && element.contextReceiverParametersCount == 0) {
element.correspondingPropertySymbol?.owner?.let { add(Property(it)) }
}
}
}
private fun IrProperty.isStatic(currentContainer: IrDeclarationContainer) =
getterIfDeclared(currentContainer)?.isStatic ?: backingField?.isStatic ?: error("Property without both getter and backing field")
getterIfDeclared(currentContainer)?.isStatic
?: backingFieldIfNotDelegate?.isStatic
?: error("Property without both getter and backing field")
fun getRootNode(context: JvmBackendContext, mfvc: IrClass): RootMfvcNode {
require(mfvc.isMultiFieldValueClass) { "${mfvc.defaultType.render()} does not require flattening" }
@@ -270,7 +283,7 @@ fun getRootNode(context: JvmBackendContext, mfvc: IrClass): RootMfvcNode {
val fields = mfvcNodeWithSubnodesImpl.fields!!
val newPrimaryConstructor = makeMfvcPrimaryConstructor(context, oldPrimaryConstructor, mfvc, leaves, fields)
val primaryConstructorImpl = makePrimaryConstructorImpl(context, oldPrimaryConstructor, mfvc, leaves)
val primaryConstructorImpl = makePrimaryConstructorImpl(context, oldPrimaryConstructor, mfvc, leaves, mfvcNodeWithSubnodesImpl)
val boxMethod = makeBoxMethod(context, mfvc, leaves, newPrimaryConstructor)
val customEqualsAny = mfvc.functions.singleOrNull {
@@ -358,7 +371,8 @@ private fun makePrimaryConstructorImpl(
context: JvmBackendContext,
oldPrimaryConstructor: IrConstructor,
mfvc: IrClass,
leaves: List<LeafMfvcNode>
leaves: List<LeafMfvcNode>,
subnodesImpl: MfvcNodeWithSubnodesImpl,
) = context.irFactory.buildFun {
name = InlineClassAbi.mangledNameFor(oldPrimaryConstructor, false, false)
visibility = oldPrimaryConstructor.visibility
@@ -371,6 +385,14 @@ private fun makePrimaryConstructorImpl(
for (leaf in leaves) {
addValueParameter(leaf.fullFieldName, leaf.type.substitute(mfvc.typeParameters, typeParameters.map { it.defaultType }))
}
for ((index, oldParameter) in oldPrimaryConstructor.valueParameters.withIndex()) {
val node = subnodesImpl.subnodes[index]
if (node is LeafMfvcNode) {
val newIndex = subnodesImpl.subnodeIndices[node]!!.first
valueParameters[newIndex].annotations = oldParameter.annotations
}
}
annotations = oldPrimaryConstructor.annotations
// body is added in the Lowering file as it needs to be lowered
}
@@ -406,7 +428,7 @@ private fun makeRootMfvcNodeSubnodes(
) = representation.underlyingPropertyNamesToTypes.mapIndexed { index, (name, type) ->
val typeArguments = makeTypeArgumentsFromType(type)
val oldProperty = properties[false to name]!!
val oldBackingField = oldProperty.backingField
val oldBackingField = oldProperty.backingFieldIfNotDelegate
val oldGetter = oldProperty.getterIfDeclared(mfvc)
val overriddenNode = oldGetter?.let { getOverriddenNode(context.multiFieldValueClassReplacements, it) as IntermediateMfvcNode? }
val static = oldProperty.isStatic(mfvc)
@@ -448,7 +470,7 @@ fun createIntermediateNodeForMfvcPropertyOfRegularClass(
oldProperty: IrProperty,
): IntermediateMfvcNode {
val oldGetter = oldProperty.getterIfDeclared(parent)
val oldField = oldProperty.backingField
val oldField = oldProperty.backingFieldIfNotDelegate
val type = oldProperty.getter?.returnType ?: oldField?.type ?: error("Either getter or field must exist")
require(type is IrSimpleType && type.needsMfvcFlattening()) { "Expected MFVC but got ${type.render()}" }
val fieldAnnotations = oldField?.annotations ?: listOf()
@@ -463,6 +485,19 @@ fun createIntermediateNodeForMfvcPropertyOfRegularClass(
}
}
fun createIntermediateNodeForStandaloneMfvcField(
parent: IrDeclarationContainer,
context: JvmBackendContext,
oldField: IrField,
): IntermediateMfvcNode {
val type = oldField.type
require(type is IrSimpleType && type.needsMfvcFlattening()) { "Expected MFVC but got ${type.render()}" }
return createIntermediateMfvcNode(
parent, context, type, makeTypeArgumentsFromType(type), oldField.name.asString(), listOf(),
oldField.annotations, oldField.isStatic, null, null, null, Modality.FINAL, oldField
)
}
private fun getOverriddenNode(replacements: MemoizedMultiFieldValueClassReplacements, getter: IrSimpleFunction): NameableMfvcNode? =
getter.overriddenSymbols
.firstOrNull { !it.owner.isFakeOverride }
@@ -482,3 +517,5 @@ fun getOptimizedPublicAccess(currentElement: IrElement?, parent: IrClass): Acces
}
private fun IrProperty.getterIfDeclared(parent: IrDeclarationContainer): IrSimpleFunction? = getter?.takeIf { it in parent.declarations }
private val IrProperty.backingFieldIfNotDelegate get() = backingField?.takeUnless { isDelegated }
@@ -0,0 +1,84 @@
@kotlin.jvm.JvmInline
@kotlin.Metadata
public final class A {
// source: 'delegating.kt'
private final field field-0: int
private final field field-1: int
private synthetic method <init>(p0: int, p1: int): void
public synthetic final static method box-impl(p0: int, p1: int): A
public final static method constructor-impl(p0: int, p1: int): void
public method equals(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean
public static method equals-impl(p0: int, p1: int, p2: java.lang.Object): boolean
public final static method equals-sUp7gFk(p0: int, p1: int, p2: int, p3: int): boolean
public final static method getValue-impl(p0: int, p1: int, @org.jetbrains.annotations.Nullable p2: java.lang.Object, @org.jetbrains.annotations.NotNull p3: kotlin.reflect.KProperty): int
public final method getX(): int
public method hashCode(): int
public static method hashCode-impl(p0: int, p1: int): int
public @org.jetbrains.annotations.NotNull method toString(): java.lang.String
public static method toString-impl(p0: int, p1: int): java.lang.String
public synthetic final method unbox-impl-0(): int
public synthetic final method unbox-impl-1(): int
}
@kotlin.Metadata
public interface Abstract {
// source: 'delegating.kt'
public abstract method getX(): int
}
@kotlin.Metadata
final class B$a$2 {
// source: 'delegating.kt'
enclosing method B.<init>(IILA;)V
public final static field INSTANCE: B$a$2
inner (anonymous) class B$a$2
static method <clinit>(): void
method <init>(): void
public final @org.jetbrains.annotations.NotNull method invoke(): A
public synthetic bridge method invoke(): java.lang.Object
}
@kotlin.Metadata
public final class B {
// source: 'delegating.kt'
synthetic final static field $$delegatedProperties: kotlin.reflect.KProperty[]
private final @org.jetbrains.annotations.NotNull field a$delegate: kotlin.Lazy
private final field b$delegate-0: int
private final field b$delegate-1: int
private field x-0: int
private field x-1: int
private @org.jetbrains.annotations.Nullable field y: A
inner (anonymous) class B$a$2
static method <clinit>(): void
private method <init>(p0: int, p1: int, p2: A): void
public synthetic method <init>(p0: int, p1: int, p2: A, p3: kotlin.jvm.internal.DefaultConstructorMarker): void
public final @org.jetbrains.annotations.NotNull method getA(): A
public synthetic final method getA-0(): int
public synthetic final method getA-1(): int
public final method getB(): int
private static method getC$delegate(p0: B): java.lang.Object
public final @org.jetbrains.annotations.NotNull method getC(): A
public synthetic final method getC-0(): int
public synthetic final method getC-1(): int
public final @org.jetbrains.annotations.NotNull method getX(): A
public synthetic final method getX-0(): int
public synthetic final method getX-1(): int
public final @org.jetbrains.annotations.Nullable method getY(): A
public final method setX-sUp7gFk(p0: int, p1: int): void
public final method setY(@org.jetbrains.annotations.Nullable p0: A): void
}
@kotlin.Metadata
public final class C {
// source: 'delegating.kt'
private synthetic final field <$$delegate_0-0>: int
private synthetic final field <$$delegate_0-1>: int
public method <init>(p0: int, p1: int): void
public method getX(): int
}
@kotlin.Metadata
public final class DelegatingKt {
// source: 'delegating.kt'
public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String
}
@@ -0,0 +1,48 @@
// !LANGUAGE: +ValueClasses
// WITH_STDLIB
// WORKS_WHEN_VALUE_CLASS
// TARGET_BACKEND: JVM_IR
// CHECK_BYTECODE_LISTING
import kotlin.reflect.KProperty
interface Abstract {
val x: Int
}
@JvmInline
value class A(override val x: Int, val y: Int): Abstract {
operator fun getValue(thisRef: Any?, property: KProperty<*>): Int {
return x + y
}
}
class B(var x: A, var y: A?) {
val a by lazy { A(-100, -200) }
val b by A(-100, -200)
val c by ::a
}
class C(a: A): Abstract by a
fun box(): String {
val a = A(1, 2)
val b = B(a, a)
require(b.x == b.y)
require(b.x.x == b.y?.x)
require(b.x.y == b.y?.y)
require(b.x.hashCode() == b.y.hashCode())
require(b.a == A(-100, -200))
require(b.a.x == -100)
require(b.a.y == -200)
require(b.b == -300)
require(b.c == A(-100, -200))
require(b.c.x == -100)
require(b.c.y == -200)
require(C(a).x == 1)
return "OK"
}
@@ -0,0 +1,84 @@
@kotlin.jvm.JvmInline
@kotlin.Metadata
public final class A {
// source: 'delegating.kt'
private final field field-0: int
private final field field-1: int
private synthetic method <init>(p0: int, p1: int): void
public synthetic final static method box-impl(p0: int, p1: int): A
public final static method constructor-impl(p0: int, p1: int): void
public method equals(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean
public static method equals-impl(p0: int, p1: int, p2: java.lang.Object): boolean
public final static method equals-sUp7gFk(p0: int, p1: int, p2: int, p3: int): boolean
public final static method getValue-impl(p0: int, p1: int, @org.jetbrains.annotations.Nullable p2: java.lang.Object, @org.jetbrains.annotations.NotNull p3: kotlin.reflect.KProperty): int
public method getX(): int
public method hashCode(): int
public static method hashCode-impl(p0: int, p1: int): int
public @org.jetbrains.annotations.NotNull method toString(): java.lang.String
public static method toString-impl(p0: int, p1: int): java.lang.String
public synthetic final method unbox-impl-0(): int
public synthetic final method unbox-impl-1(): int
}
@kotlin.Metadata
public interface Abstract {
// source: 'delegating.kt'
public abstract method getX(): int
}
@kotlin.Metadata
final class B$a$2 {
// source: 'delegating.kt'
enclosing method B.<init>(IILA;)V
public final static field INSTANCE: B$a$2
inner (anonymous) class B$a$2
static method <clinit>(): void
method <init>(): void
public final @org.jetbrains.annotations.NotNull method invoke(): A
public synthetic bridge method invoke(): java.lang.Object
}
@kotlin.Metadata
public final class B {
// source: 'delegating.kt'
synthetic final static field $$delegatedProperties: kotlin.reflect.KProperty[]
private final @org.jetbrains.annotations.NotNull field a$delegate: kotlin.Lazy
private final field b$delegate-0: int
private final field b$delegate-1: int
private field x-0: int
private field x-1: int
private @org.jetbrains.annotations.Nullable field y: A
inner (anonymous) class B$a$2
static method <clinit>(): void
private method <init>(p0: int, p1: int, p2: A): void
public synthetic method <init>(p0: int, p1: int, p2: A, p3: kotlin.jvm.internal.DefaultConstructorMarker): void
public final @org.jetbrains.annotations.NotNull method getA(): A
public synthetic final method getA-0(): int
public synthetic final method getA-1(): int
public final method getB(): int
private static method getC$delegate(p0: B): java.lang.Object
public final @org.jetbrains.annotations.NotNull method getC(): A
public synthetic final method getC-0(): int
public synthetic final method getC-1(): int
public final @org.jetbrains.annotations.NotNull method getX(): A
public synthetic final method getX-0(): int
public synthetic final method getX-1(): int
public final @org.jetbrains.annotations.Nullable method getY(): A
public final method setX-sUp7gFk(p0: int, p1: int): void
public final method setY(@org.jetbrains.annotations.Nullable p0: A): void
}
@kotlin.Metadata
public final class C {
// source: 'delegating.kt'
private synthetic final field $$delegate_0-0: int
private synthetic final field $$delegate_0-1: int
public method <init>(p0: int, p1: int): void
public method getX(): int
}
@kotlin.Metadata
public final class DelegatingKt {
// source: 'delegating.kt'
public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String
}
@@ -0,0 +1,120 @@
// !LANGUAGE: +ValueClasses
// WITH_STDLIB
// WORKS_WHEN_VALUE_CLASS
// FIR_IDENTICAL
// TARGET_BACKEND: JVM_IR
import kotlin.reflect.KProperty
@Repeatable
annotation class Ann
@[Ann Ann]
@JvmInline
value class A @Ann constructor(
@[Ann Ann]
@param:[Ann Ann]
@property:[Ann Ann]
@field:[Ann Ann]
@get:[Ann Ann]
val x: Int,
@[Ann Ann]
@param:[Ann Ann]
@property:[Ann Ann]
@field:[Ann Ann]
@get:[Ann Ann]
val y: Int,
) {
operator fun getValue(thisRef: Any?, property: KProperty<*>): Int {
return 0
}
}
@[Ann Ann]
@JvmInline
value class B @Ann constructor(
@property:[Ann Ann]
val x: A,
@[Ann Ann]
@param:[Ann Ann]
@property:[Ann Ann]
@field:[Ann Ann]
@get:[Ann Ann]
val y: A?,
)
@[Ann Ann]
class C @Ann constructor(
@property:[Ann Ann]
@set:[Ann Ann]
var x: A,
@[Ann Ann]
@param:[Ann Ann]
@property:[Ann Ann]
@field:[Ann Ann]
@get:[Ann Ann]
@set:[Ann Ann]
@setparam:[Ann Ann]
var y: A?,
) {
@delegate:[Ann Ann]
@property:[Ann Ann]
val z by lazy { A(-100, -200) }
@property:[Ann Ann]
@get:[Ann Ann]
val t by A(-100, -200)
@property:[Ann Ann]
val d by ::z
init {
if (2 + 2 == 4) {
@[Ann Ann]
val x = 4
val y = A(1, 2)
}
fun f() {
if (2 + 2 == 4) {
@[Ann Ann]
val x = 4
val y = A(1, 2)
}
}
}
}
@[Ann Ann]
fun A.t(a: A, b: B, @[Ann Ann] c: C) {
if (2 + 2 == 4) {
@[Ann Ann]
val x = 4
val y = A(1, 2)
}
fun f() {
if (2 + 2 == 4) {
@[Ann Ann]
val x1 = 4
val y1 = A(1, 2)
}
}
}
@[Ann Ann]
fun @receiver:[Ann Ann] C.t(a: A, b: B, @[Ann Ann] c: C) = 4
@[Ann Ann]
var A.t
@[Ann Ann]
get() = A(1, 2)
@[Ann Ann]
set(_) = Unit
@[Ann Ann]
var @receiver:[Ann Ann] C.t
@[Ann Ann]
get() = A(1, 2)
@[Ann Ann]
set(_) = Unit
@@ -0,0 +1,134 @@
@Ann$Container(value=[Ann, Ann])
@kotlin.jvm.JvmInline
@kotlin.Metadata
public final class A {
// source: 'annotations.kt'
private final @Ann$Container(value=[Ann, Ann]) field field-0: int
private final @Ann$Container(value=[Ann, Ann]) field field-1: int
private synthetic method <init>(p0: int, p1: int): void
public synthetic final static method box-impl(p0: int, p1: int): A
public final static @Ann method constructor-impl(@Ann$Container(value=[Ann, Ann, Ann, Ann]) p0: int, @Ann$Container(value=[Ann, Ann, Ann, Ann]) p1: int): void
public method equals(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean
public static method equals-impl(p0: int, p1: int, p2: java.lang.Object): boolean
public final static method equals-sUp7gFk(p0: int, p1: int, p2: int, p3: int): boolean
public final static method getValue-impl(p0: int, p1: int, @org.jetbrains.annotations.Nullable p2: java.lang.Object, @org.jetbrains.annotations.NotNull p3: kotlin.reflect.KProperty): int
public synthetic deprecated static @Ann$Container(value=[Ann, Ann]) method getX$annotations(): void
public synthetic deprecated static @Ann$Container(value=[Ann, Ann]) method getY$annotations(): void
public method hashCode(): int
public static method hashCode-impl(p0: int, p1: int): int
public @org.jetbrains.annotations.NotNull method toString(): java.lang.String
public static method toString-impl(p0: int, p1: int): java.lang.String
public synthetic final method unbox-impl-0(): int
public synthetic final method unbox-impl-1(): int
public inner class Ann$Container
}
@kotlin.jvm.internal.RepeatableContainer
@java.lang.annotation.Retention(value=RUNTIME)
@kotlin.Metadata
public annotation class Ann$Container {
// source: 'annotations.kt'
public abstract method value(): Ann[]
public inner class Ann$Container
}
@kotlin.annotation.Repeatable
@java.lang.annotation.Retention(value=RUNTIME)
@java.lang.annotation.Repeatable(value=Ann$Container::class)
@kotlin.Metadata
public annotation class Ann {
// source: 'annotations.kt'
public inner class Ann$Container
}
@kotlin.Metadata
public final class AnnotationsKt {
// source: 'annotations.kt'
public synthetic deprecated static @Ann$Container(value=[Ann, Ann]) method getT$annotations(p0: A): void
public synthetic deprecated static @Ann$Container(value=[Ann, Ann]) method getT$annotations(p0: C): void
public final static @Ann$Container(value=[Ann, Ann]) @org.jetbrains.annotations.NotNull method getT(@Ann$Container(value=[Ann, Ann]) @org.jetbrains.annotations.NotNull p0: C): A
public final static @Ann$Container(value=[Ann, Ann]) @org.jetbrains.annotations.NotNull method getT-sUp7gFk(p0: int, p1: int): A
public final static @Ann$Container(value=[Ann, Ann]) method setT-GPBa7dw(@Ann$Container(value=[Ann, Ann]) @org.jetbrains.annotations.NotNull p0: C, p1: int, p2: int): void
public final static @Ann$Container(value=[Ann, Ann]) method setT-GPBa7dw(p0: int, p1: int, p2: int, p3: int): void
public final static @Ann$Container(value=[Ann, Ann]) method t-552ch2I(@Ann$Container(value=[Ann, Ann]) @org.jetbrains.annotations.NotNull p0: C, p1: int, p2: int, p3: int, p4: int, @org.jetbrains.annotations.Nullable p5: A, @Ann$Container(value=[Ann, Ann]) @org.jetbrains.annotations.NotNull p6: C): int
public final static @Ann$Container(value=[Ann, Ann]) method t-552ch2I(p0: int, p1: int, p2: int, p3: int, p4: int, p5: int, @org.jetbrains.annotations.Nullable p6: A, @Ann$Container(value=[Ann, Ann]) @org.jetbrains.annotations.NotNull p7: C): void
private final static method t_552ch2I$f(): void
public inner class Ann$Container
}
@Ann$Container(value=[Ann, Ann])
@kotlin.jvm.JvmInline
@kotlin.Metadata
public final class B {
// source: 'annotations.kt'
private final field field-0-0: int
private final field field-0-1: int
private final @Ann$Container(value=[Ann, Ann]) @org.jetbrains.annotations.Nullable field field-1: A
private synthetic method <init>(p0: int, p1: int, p2: A): void
public synthetic final static method box-impl(p0: int, p1: int, p2: A): B
public final static @Ann method constructor-impl(p0: int, p1: int, @Ann$Container(value=[Ann, Ann, Ann, Ann]) @org.jetbrains.annotations.Nullable p2: A): void
public method equals(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean
public static method equals-impl(p0: int, p1: int, p2: A, p3: java.lang.Object): boolean
public final static method equals-sUp7gFk(p0: int, p1: int, p2: A, p3: int, p4: int, p5: A): boolean
public synthetic deprecated static @Ann$Container(value=[Ann, Ann]) method getX$annotations(): void
public synthetic deprecated static @Ann$Container(value=[Ann, Ann]) method getY$annotations(): void
public method hashCode(): int
public static method hashCode-impl(p0: int, p1: int, p2: A): int
public @org.jetbrains.annotations.NotNull method toString(): java.lang.String
public static method toString-impl(p0: int, p1: int, p2: A): java.lang.String
public synthetic final method unbox-impl-0(): A
public synthetic final method unbox-impl-0-0(): int
public synthetic final method unbox-impl-0-1(): int
public synthetic final method unbox-impl-1(): A
public inner class Ann$Container
}
@kotlin.Metadata
final class C$z$2 {
// source: 'annotations.kt'
enclosing method C.<init>(IILA;)V
public final static field INSTANCE: C$z$2
inner (anonymous) class C$z$2
static method <clinit>(): void
method <init>(): void
public final @org.jetbrains.annotations.NotNull method invoke(): A
public synthetic bridge method invoke(): java.lang.Object
}
@Ann$Container(value=[Ann, Ann])
@kotlin.Metadata
public final class C {
// source: 'annotations.kt'
synthetic final static field $$delegatedProperties: kotlin.reflect.KProperty[]
private final field t$delegate-0: int
private final field t$delegate-1: int
private field x-0: int
private field x-1: int
private @Ann$Container(value=[Ann, Ann]) @org.jetbrains.annotations.Nullable field y: A
private final @Ann$Container(value=[Ann, Ann]) @org.jetbrains.annotations.NotNull field z$delegate: kotlin.Lazy
inner (anonymous) class C$z$2
static method <clinit>(): void
public synthetic @Ann method <init>(p0: int, p1: int, @Ann$Container(value=[Ann, Ann, Ann, Ann]) p2: A, p3: kotlin.jvm.internal.DefaultConstructorMarker): void
private method <init>(p0: int, p1: int, p2: A): void
private final static method _init_$f(): void
public synthetic deprecated static @Ann$Container(value=[Ann, Ann]) method getD$annotations(): void
private static method getD$delegate(p0: C): java.lang.Object
public final @org.jetbrains.annotations.NotNull method getD(): A
public synthetic final method getD-0(): int
public synthetic final method getD-1(): int
public synthetic deprecated static @Ann$Container(value=[Ann, Ann]) method getT$annotations(): void
public final @Ann$Container(value=[Ann, Ann]) method getT(): int
public synthetic deprecated static @Ann$Container(value=[Ann, Ann]) method getX$annotations(): void
public final @org.jetbrains.annotations.NotNull method getX(): A
public synthetic final method getX-0(): int
public synthetic final method getX-1(): int
public synthetic deprecated static @Ann$Container(value=[Ann, Ann]) method getY$annotations(): void
public final @Ann$Container(value=[Ann, Ann]) @org.jetbrains.annotations.Nullable method getY(): A
public synthetic deprecated static @Ann$Container(value=[Ann, Ann]) method getZ$annotations(): void
public final @org.jetbrains.annotations.NotNull method getZ(): A
public synthetic final method getZ-0(): int
public synthetic final method getZ-1(): int
public final @Ann$Container(value=[Ann, Ann]) method setX-sUp7gFk(p0: int, p1: int): void
public final @Ann$Container(value=[Ann, Ann]) method setY(@Ann$Container(value=[Ann, Ann]) @org.jetbrains.annotations.Nullable p0: A): void
public inner class Ann$Container
}
@@ -4,6 +4,8 @@
// WORKS_WHEN_VALUE_CLASS
// FIR_IDENTICAL
import kotlin.reflect.KProperty
@Repeatable
annotation class Ann
@@ -22,7 +24,11 @@ value class A @Ann constructor(
@field:[Ann Ann]
@get:[Ann Ann]
val y: Int,
)
) {
operator fun getValue(thisRef: Any?, property: KProperty<*>): Int {
return 0
}
}
@[Ann Ann]
@JvmInline
@@ -63,8 +69,18 @@ class C @Ann constructor(
@setparam:[Ann Ann]
var y: A?,
) {
@delegate:[<!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!> <!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!>]
@delegate:[Ann Ann]
@property:[Ann Ann]
@get:[<!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!> <!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!>]
val z by lazy { A(-100, -200) }
@delegate:[<!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!> <!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!>]
@property:[Ann Ann]
@get:[Ann Ann]
val c by A(-100, -200)
@delegate:[Ann Ann]
@property:[Ann Ann]
@get:[<!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!> <!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!>]
val d by ::z
<!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET, INAPPLICABLE_JVM_FIELD!>@JvmField<!>
val e = x
@@ -91,7 +107,7 @@ class C @Ann constructor(
@[Ann Ann]
fun @receiver:[Ann Ann] A.t(@[<!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!> <!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!>] a: A, @[<!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!> <!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!>] b: B, @[Ann Ann] c: C) {
fun @receiver:[<!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!> <!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!>] A.t(@[<!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!> <!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!>] a: A, @[<!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!> <!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!>] b: B, @[Ann Ann] c: C) {
if (2 + 2 == 4) {
@[Ann Ann]
val x = 4
@@ -111,3 +127,17 @@ fun @receiver:[Ann Ann] A.t(@[<!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TY
@[Ann Ann]
fun @receiver:[Ann Ann] C.t(@[<!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!> <!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!>] a: A, @[<!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!> <!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!>] b: B, @[Ann Ann] c: C) = 4
@[Ann Ann]
var @receiver:[<!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!> <!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!>] A.t
@[Ann Ann]
get() = A(1, 2)
@[Ann Ann]
set(@[<!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!> <!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!>] _) = Unit
@[Ann Ann]
var @receiver:[Ann Ann] C.t
@[Ann Ann]
get() = A(1, 2)
@[Ann Ann]
set(@[<!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!> <!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!>] _) = Unit
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.test.runners.codegen;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.util.KtTestUtil;
import org.jetbrains.kotlin.test.TargetBackend;
import org.jetbrains.kotlin.test.utils.TransformersFunctions;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
@@ -2410,4 +2411,14 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest {
}
}
}
@Nested
@TestMetadata("compiler/testData/codegen/bytecodeListing/valueClasses")
@TestDataPath("$PROJECT_ROOT")
public class ValueClasses {
@Test
public void testAllFilesPresentInValueClasses() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeListing/valueClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
}
}
}
@@ -50447,6 +50447,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/valueClasses/defaultParameters.kt", TransformersFunctions.getReplaceOptionalJvmInlineAnnotationWithReal());
}
@Test
@TestMetadata("delegating.kt")
public void testDelegating() throws Exception {
runTest("compiler/testData/codegen/box/valueClasses/delegating.kt", TransformersFunctions.getReplaceOptionalJvmInlineAnnotationWithReal());
}
@Test
@TestMetadata("equality.kt")
public void testEquality() throws Exception {
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.test.runners.codegen;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.util.KtTestUtil;
import org.jetbrains.kotlin.test.TargetBackend;
import org.jetbrains.kotlin.test.utils.TransformersFunctions;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
@@ -2512,4 +2513,20 @@ public class IrBytecodeListingTestGenerated extends AbstractIrBytecodeListingTes
}
}
}
@Nested
@TestMetadata("compiler/testData/codegen/bytecodeListing/valueClasses")
@TestDataPath("$PROJECT_ROOT")
public class ValueClasses {
@Test
public void testAllFilesPresentInValueClasses() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeListing/valueClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@Test
@TestMetadata("annotations.kt")
public void testAnnotations() throws Exception {
runTest("compiler/testData/codegen/bytecodeListing/valueClasses/annotations.kt", TransformersFunctions.getReplaceOptionalJvmInlineAnnotationWithReal());
}
}
}