diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ErasedInlineClassBodyCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/ErasedInlineClassBodyCodegen.kt index 2fad45da68f..b95fa52c5c3 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ErasedInlineClassBodyCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ErasedInlineClassBodyCodegen.kt @@ -11,6 +11,7 @@ import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.psi.KtClass +import org.jetbrains.kotlin.psi.KtClassOrObject import org.jetbrains.kotlin.resolve.InlineClassDescriptorResolver import org.jetbrains.kotlin.resolve.descriptorUtil.secondaryConstructors import org.jetbrains.kotlin.resolve.jvm.diagnostics.Synthetic @@ -61,6 +62,13 @@ class ErasedInlineClassBodyCodegen( super.generateSyntheticPartsAfterBody() generateUnboxMethod() + generateFunctionsFromAny() + } + + private fun generateFunctionsFromAny() { + FunctionsFromAnyGeneratorImpl( + myClass as KtClassOrObject, bindingContext, descriptor, classAsmType, context, v, state + ).generate() } private fun generateUnboxMethod() { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java index 16f9ec4c54a..981a5045fbc 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java @@ -256,7 +256,7 @@ public class FunctionCodegen { ); } else if (shouldDelegateMethodBodyToInlineClass(origin, functionDescriptor, contextKind, containingDeclaration, bindingContext)) { - generateMethodInsideInlineClassWrapper(origin, functionDescriptor, (ClassDescriptor) containingDeclaration, mv); + generateMethodInsideInlineClassWrapper(origin, functionDescriptor, (ClassDescriptor) containingDeclaration, mv, typeMapper); } else { generateMethodBody( @@ -304,11 +304,12 @@ public class FunctionCodegen { return isInlineClass && simpleFunctionOrProperty; } - private void generateMethodInsideInlineClassWrapper( + public static void generateMethodInsideInlineClassWrapper( @NotNull JvmDeclarationOrigin origin, @NotNull FunctionDescriptor functionDescriptor, - ClassDescriptor containingDeclaration, - MethodVisitor mv + @NotNull ClassDescriptor containingDeclaration, + @NotNull MethodVisitor mv, + @NotNull KotlinTypeMapper typeMapper ) { mv.visitCode(); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionsFromAnyGeneratorImpl.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionsFromAnyGeneratorImpl.java index 039907dbaf8..52ea3a5b352 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionsFromAnyGeneratorImpl.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionsFromAnyGeneratorImpl.java @@ -18,8 +18,11 @@ import org.jetbrains.kotlin.descriptors.PropertyDescriptor; import org.jetbrains.kotlin.lexer.KtTokens; import org.jetbrains.kotlin.psi.KtClassOrObject; import org.jetbrains.kotlin.resolve.BindingContext; +import org.jetbrains.kotlin.resolve.InlineClassesUtilsKt; +import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin; import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt; import org.jetbrains.kotlin.types.KotlinType; +import org.jetbrains.kotlin.types.SimpleType; import org.jetbrains.org.objectweb.asm.Label; import org.jetbrains.org.objectweb.asm.MethodVisitor; import org.jetbrains.org.objectweb.asm.Type; @@ -31,6 +34,7 @@ import static org.jetbrains.kotlin.codegen.AsmUtil.*; import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.JAVA_STRING_TYPE; import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE; import static org.jetbrains.org.objectweb.asm.Opcodes.ACC_PUBLIC; +import static org.jetbrains.org.objectweb.asm.Opcodes.ACC_STATIC; import static org.jetbrains.org.objectweb.asm.Opcodes.IRETURN; public class FunctionsFromAnyGeneratorImpl extends FunctionsFromAnyGenerator { @@ -40,6 +44,7 @@ public class FunctionsFromAnyGeneratorImpl extends FunctionsFromAnyGenerator { private final ClassBuilder v; private final GenerationState generationState; private final KotlinTypeMapper typeMapper; + private final JvmKotlinType underlyingType; public FunctionsFromAnyGeneratorImpl( @NotNull KtClassOrObject declaration, @@ -57,6 +62,10 @@ public class FunctionsFromAnyGeneratorImpl extends FunctionsFromAnyGenerator { this.v = v; this.generationState = state; this.typeMapper = state.getTypeMapper(); + this.underlyingType = new JvmKotlinType( + typeMapper.mapType(descriptor), + InlineClassesUtilsKt.substitutedUnderlyingType(descriptor.getDefaultType()) + ); } @Override @@ -64,7 +73,14 @@ public class FunctionsFromAnyGeneratorImpl extends FunctionsFromAnyGenerator { @NotNull FunctionDescriptor function, @NotNull List properties ) { MethodContext context = fieldOwnerContext.intoFunction(function); - MethodVisitor mv = v.newMethod(JvmDeclarationOriginKt.OtherOrigin(function), ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null); + JvmDeclarationOrigin methodOrigin = JvmDeclarationOriginKt.OtherOrigin(function); + MethodVisitor mv = v.newMethod(methodOrigin, getAccess(), "toString", getToStringDesc(), null, null); + + if (fieldOwnerContext.getContextKind() != OwnerKind.ERASED_INLINE_CLASS && classDescriptor.isInline()) { + FunctionCodegen.generateMethodInsideInlineClassWrapper(methodOrigin, function, classDescriptor, mv, typeMapper); + return; + } + mv.visitAnnotation(Type.getDescriptor(NotNull.class), false); InstructionAdapter iv = new InstructionAdapter(mv); @@ -82,9 +98,7 @@ public class FunctionsFromAnyGeneratorImpl extends FunctionsFromAnyGenerator { } genInvokeAppendMethod(iv, JAVA_STRING_TYPE, null); - JvmKotlinType type = ImplementationBodyCodegen.genPropertyOnStack( - iv, context, propertyDescriptor, classAsmType, 0, generationState - ); + JvmKotlinType type = genOrLoadOnStack(iv, context, propertyDescriptor, 0); Type asmType = type.getType(); if (asmType.getSort() == Type.ARRAY) { @@ -117,7 +131,14 @@ public class FunctionsFromAnyGeneratorImpl extends FunctionsFromAnyGenerator { @NotNull FunctionDescriptor function, @NotNull List properties ) { MethodContext context = fieldOwnerContext.intoFunction(function); - MethodVisitor mv = v.newMethod(JvmDeclarationOriginKt.OtherOrigin(function), ACC_PUBLIC, "hashCode", "()I", null, null); + JvmDeclarationOrigin methodOrigin = JvmDeclarationOriginKt.OtherOrigin(function); + MethodVisitor mv = v.newMethod(methodOrigin, getAccess(), "hashCode", getHashCodeDesc(), null, null); + + if (fieldOwnerContext.getContextKind() != OwnerKind.ERASED_INLINE_CLASS && classDescriptor.isInline()) { + FunctionCodegen.generateMethodInsideInlineClassWrapper(methodOrigin, function, classDescriptor, mv, typeMapper); + return; + } + InstructionAdapter iv = new InstructionAdapter(mv); mv.visitCode(); @@ -128,9 +149,7 @@ public class FunctionsFromAnyGeneratorImpl extends FunctionsFromAnyGenerator { iv.mul(Type.INT_TYPE); } - JvmKotlinType propertyType = ImplementationBodyCodegen.genPropertyOnStack( - iv, context, propertyDescriptor, classAsmType, 0, generationState - ); + JvmKotlinType propertyType = genOrLoadOnStack(iv, context, propertyDescriptor, 0); KotlinType kotlinType = propertyDescriptor.getReturnType(); Type asmType = typeMapper.mapType(kotlinType); StackValue.coerce(propertyType.getType(), propertyType.getKotlinType(), asmType, kotlinType, iv); @@ -172,39 +191,32 @@ public class FunctionsFromAnyGeneratorImpl extends FunctionsFromAnyGenerator { @NotNull FunctionDescriptor function, @NotNull List properties ) { MethodContext context = fieldOwnerContext.intoFunction(function); - MethodVisitor - mv = v.newMethod(JvmDeclarationOriginKt.OtherOrigin(function), ACC_PUBLIC, "equals", "(Ljava/lang/Object;)Z", null, null); - mv.visitParameterAnnotation(0, Type.getDescriptor(Nullable.class), false); + JvmDeclarationOrigin methodOrigin = JvmDeclarationOriginKt.OtherOrigin(function); + MethodVisitor mv = v.newMethod(methodOrigin, getAccess(), "equals", getEqualsDesc(), null, null); + + boolean isErasedInlineClassKind = fieldOwnerContext.getContextKind() == OwnerKind.ERASED_INLINE_CLASS; + if (!isErasedInlineClassKind && classDescriptor.isInline()) { + FunctionCodegen.generateMethodInsideInlineClassWrapper(methodOrigin, function, classDescriptor, mv, typeMapper); + return; + } + + mv.visitParameterAnnotation(isErasedInlineClassKind ? 1 : 0, Type.getDescriptor(Nullable.class), false); InstructionAdapter iv = new InstructionAdapter(mv); mv.visitCode(); Label eq = new Label(); Label ne = new Label(); - iv.load(0, OBJECT_TYPE); - iv.load(1, OBJECT_TYPE); - iv.ifacmpeq(eq); - - iv.load(1, OBJECT_TYPE); - iv.instanceOf(classAsmType); - iv.ifeq(ne); - - iv.load(1, OBJECT_TYPE); - iv.checkcast(classAsmType); - iv.store(2, OBJECT_TYPE); + int storedValueIndex = generateBasicChecksAndStoreTarget(iv, eq, ne); for (PropertyDescriptor propertyDescriptor : properties) { KotlinType kotlinType = propertyDescriptor.getReturnType(); Type asmType = typeMapper.mapType(kotlinType); - JvmKotlinType thisPropertyType = ImplementationBodyCodegen.genPropertyOnStack( - iv, context, propertyDescriptor, classAsmType, 0, generationState - ); + JvmKotlinType thisPropertyType = genOrLoadOnStack(iv,context, propertyDescriptor, 0); StackValue.coerce(thisPropertyType.getType(), thisPropertyType.getKotlinType(), asmType, kotlinType, iv); - JvmKotlinType otherPropertyType = ImplementationBodyCodegen.genPropertyOnStack( - iv, context, propertyDescriptor, classAsmType, 2, generationState - ); + JvmKotlinType otherPropertyType = genOrLoadOnStack(iv,context, propertyDescriptor, storedValueIndex); StackValue.coerce(otherPropertyType.getType(), otherPropertyType.getKotlinType(), asmType, kotlinType, iv); if (asmType.getSort() == Type.FLOAT) { @@ -234,4 +246,77 @@ public class FunctionsFromAnyGeneratorImpl extends FunctionsFromAnyGenerator { FunctionCodegen.endVisit(mv, "equals", getDeclaration()); } + + private int generateBasicChecksAndStoreTarget(InstructionAdapter iv, Label eq, Label ne) { + if (fieldOwnerContext.getContextKind() == OwnerKind.ERASED_INLINE_CLASS) { + SimpleType wrapperKotlinType = classDescriptor.getDefaultType(); + Type wrapperType = typeMapper.mapTypeAsDeclaration(wrapperKotlinType); + int secondParameterIndex = underlyingType.getType().getSize(); + + iv.load(secondParameterIndex, OBJECT_TYPE); + iv.instanceOf(wrapperType); + iv.ifeq(ne); + + int unboxedValueIndex = secondParameterIndex + 1; + + iv.load(secondParameterIndex, OBJECT_TYPE); + iv.checkcast(wrapperType); + StackValue.unboxInlineClass(wrapperType, wrapperKotlinType, iv); + iv.store(unboxedValueIndex, underlyingType.getType()); + + return unboxedValueIndex; + } + else { + iv.load(0, OBJECT_TYPE); + iv.load(1, OBJECT_TYPE); + iv.ifacmpeq(eq); + + iv.load(1, OBJECT_TYPE); + iv.instanceOf(classAsmType); + iv.ifeq(ne); + + iv.load(1, OBJECT_TYPE); + iv.checkcast(classAsmType); + iv.store(2, OBJECT_TYPE); + + return 2; + } + } + + private JvmKotlinType genOrLoadOnStack(InstructionAdapter iv, MethodContext context, PropertyDescriptor propertyDescriptor, int index) { + if (fieldOwnerContext.getContextKind() == OwnerKind.ERASED_INLINE_CLASS) { + iv.load(index, underlyingType.getType()); + return underlyingType; + } + else { + return ImplementationBodyCodegen.genPropertyOnStack( + iv, context, propertyDescriptor, classAsmType, index, generationState + ); + } + } + + private String getToStringDesc() { + return "(" + getFirstParameterDesc() + ")Ljava/lang/String;"; + } + + private String getHashCodeDesc() { + return "(" + getFirstParameterDesc() + ")I"; + } + + private String getEqualsDesc() { + return "(" + getFirstParameterDesc() + "Ljava/lang/Object;)Z"; + } + + private String getFirstParameterDesc() { + return fieldOwnerContext.getContextKind() == OwnerKind.ERASED_INLINE_CLASS ? underlyingType.getType().getDescriptor() : ""; + } + + private int getAccess() { + int access = ACC_PUBLIC; + if (fieldOwnerContext.getContextKind() == OwnerKind.ERASED_INLINE_CLASS) { + access |= ACC_STATIC; + } + + return access; + } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java index 168e443f535..59a9cebe40b 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java @@ -434,6 +434,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { generateFunctionsForDataClasses(); + generateFunctionsFromAnyForInlineClasses(); + if (state.getClassBuilderMode() != ClassBuilderMode.LIGHT_CLASSES) { new CollectionStubMethodGenerator(typeMapper, descriptor).generate(functionCodegen, v); @@ -556,6 +558,14 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { new DataClassMethodGeneratorImpl((KtClassOrObject)myClass, bindingContext).generate(); } + private void generateFunctionsFromAnyForInlineClasses() { + if (!descriptor.isInline()) return; + if (!(myClass instanceof KtClassOrObject)) return; + new FunctionsFromAnyGeneratorImpl( + (KtClassOrObject) myClass, bindingContext, descriptor, classAsmType, context, v, state + ).generate(); + } + private class DataClassMethodGeneratorImpl extends DataClassMethodGenerator { private final FunctionsFromAnyGeneratorImpl functionsFromAnyGenerator; diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java index e0d2af05645..a1660ce8f8d 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java @@ -410,7 +410,7 @@ public abstract class StackValue { ); } - private static void unboxInlineClass(@NotNull Type type, @NotNull KotlinType targetInlineClassType, @NotNull InstructionAdapter v) { + public static void unboxInlineClass(@NotNull Type type, @NotNull KotlinType targetInlineClassType, @NotNull InstructionAdapter v) { Type owner = KotlinTypeMapper.mapInlineClassTypeAsDeclaration(targetInlineClassType); coerce(type, owner, v); diff --git a/compiler/testData/codegen/box/inlineClasses/defaultFunctionsFromAnyForInlineClass.kt b/compiler/testData/codegen/box/inlineClasses/defaultFunctionsFromAnyForInlineClass.kt new file mode 100644 index 00000000000..ea01e558527 --- /dev/null +++ b/compiler/testData/codegen/box/inlineClasses/defaultFunctionsFromAnyForInlineClass.kt @@ -0,0 +1,51 @@ +// !LANGUAGE: +InlineClasses +// IGNORE_BACKEND: JVM_IR, JS_IR, JS + +inline class Foo(val x: Int) +inline class FooRef(val y: String) +inline class FooLong(val x: Long) +inline class FooDouble(val y: Double) + +fun box(): String { + val f = Foo(42) + if (f.toString() != "Foo(x=42)") return "Fail 1: $f" + + if (!f.equals(f)) return "Fail 2" + + val g = Foo(43) + if (f.equals(g)) return "Fail 3" + + if (42.hashCode() != f.hashCode()) return "Fail 4" + + val fRef = FooRef("42") + if (fRef.toString() != "FooRef(y=42)") return "Fail 5: $fRef" + + if (!fRef.equals(fRef)) return "Fail 6" + + val gRef = FooRef("43") + if (fRef.equals(gRef)) return "Fail 7" + + if ("42".hashCode() != fRef.hashCode()) return "Fail 8" + + val fLong = FooLong(42) + if (fLong.toString() != "FooLong(x=42)") return "Fail 9: $fLong" + + if (!fLong.equals(fLong)) return "Fail 10" + + val gLong = FooLong(43) + if (fLong.equals(gLong)) return "Fail 11" + + if (42L.hashCode() != fLong.hashCode()) return "Fail 12" + + val fDouble = FooDouble(42.0) + if (fDouble.toString() != "FooDouble(y=42.0)") return "Fail 13: $fDouble" + + if (!fDouble.equals(fDouble)) return "Fail 14" + + val gDouble = FooDouble(43.0) + if (fDouble.equals(gDouble)) return "Fail 15" + + if (42.0.hashCode() != fDouble.hashCode()) return "Fail 16" + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeListing/inlineClasses/companionObjectInsideInlineClass.txt b/compiler/testData/codegen/bytecodeListing/inlineClasses/companionObjectInsideInlineClass.txt index 8c1aaf4ef55..b29d85b411d 100644 --- a/compiler/testData/codegen/bytecodeListing/inlineClasses/companionObjectInsideInlineClass.txt +++ b/compiler/testData/codegen/bytecodeListing/inlineClasses/companionObjectInsideInlineClass.txt @@ -10,7 +10,10 @@ public final class Foo$Companion { public final static class Foo$Erased { public final static @org.jetbrains.annotations.NotNull method box(p0: int): Foo public static method constructor(p0: int): int + public static method equals(p0: int, @org.jetbrains.annotations.Nullable p1: java.lang.Object): boolean + public static method hashCode(p0: int): int public final static method inInlineClass(p0: int): void + public static @org.jetbrains.annotations.NotNull method toString(p0: int): java.lang.String } @kotlin.Metadata @@ -21,7 +24,10 @@ public final class Foo { inner class Foo$Companion static method (): void public method (p0: int): void + public method equals(p0: java.lang.Object): boolean public final method getX(): int + public method hashCode(): int public final method inInlineClass(): void + public method toString(): java.lang.String public final method unbox(): int } diff --git a/compiler/testData/codegen/bytecodeListing/inlineClasses/computablePropertiesInsideInlineClass.txt b/compiler/testData/codegen/bytecodeListing/inlineClasses/computablePropertiesInsideInlineClass.txt index f9755e53e69..b248450aba2 100644 --- a/compiler/testData/codegen/bytecodeListing/inlineClasses/computablePropertiesInsideInlineClass.txt +++ b/compiler/testData/codegen/bytecodeListing/inlineClasses/computablePropertiesInsideInlineClass.txt @@ -2,16 +2,22 @@ public final static class Foo$Erased { public final static @org.jetbrains.annotations.NotNull method box(p0: int): Foo public static method constructor(p0: int): int + public static method equals(p0: int, @org.jetbrains.annotations.Nullable p1: java.lang.Object): boolean public final static method getAsThis(p0: int): int public final static method getProp(p0: int): int + public static method hashCode(p0: int): int + public static @org.jetbrains.annotations.NotNull method toString(p0: int): java.lang.String } @kotlin.Metadata public final class Foo { private final field x: int public method (p0: int): void + public method equals(p0: java.lang.Object): boolean public final method getAsThis(): int public final method getProp(): int public final method getX(): int + public method hashCode(): int + public method toString(): java.lang.String public final method unbox(): int } diff --git a/compiler/testData/codegen/bytecodeListing/inlineClasses/noBridgesForErasedInlineClass.txt b/compiler/testData/codegen/bytecodeListing/inlineClasses/noBridgesForErasedInlineClass.txt index 56917b18bde..0e44517af15 100644 --- a/compiler/testData/codegen/bytecodeListing/inlineClasses/noBridgesForErasedInlineClass.txt +++ b/compiler/testData/codegen/bytecodeListing/inlineClasses/noBridgesForErasedInlineClass.txt @@ -7,15 +7,21 @@ public interface A { public final static class Foo$Erased { public final static @org.jetbrains.annotations.NotNull method box(p0: long): Foo public static method constructor(p0: long): long + public static method equals(p0: long, @org.jetbrains.annotations.Nullable p1: java.lang.Object): boolean public static method foo(p0: long, p1: long): void + public static method hashCode(p0: long): int + public static @org.jetbrains.annotations.NotNull method toString(p0: long): java.lang.String } @kotlin.Metadata public final class Foo { private final field x: long public method (p0: long): void + public method equals(p0: java.lang.Object): boolean public synthetic method foo(p0: java.lang.Object): void public method foo(p0: long): void public final method getX(): long + public method hashCode(): int + public method toString(): java.lang.String public final method unbox(): long } diff --git a/compiler/testData/codegen/bytecodeListing/inlineClasses/shapeOfInlineClassWithPrimitive.txt b/compiler/testData/codegen/bytecodeListing/inlineClasses/shapeOfInlineClassWithPrimitive.txt index e479540ee91..eba35f9bf13 100644 --- a/compiler/testData/codegen/bytecodeListing/inlineClasses/shapeOfInlineClassWithPrimitive.txt +++ b/compiler/testData/codegen/bytecodeListing/inlineClasses/shapeOfInlineClassWithPrimitive.txt @@ -3,8 +3,11 @@ public final static class Foo$Erased { public final static @org.jetbrains.annotations.NotNull method box(p0: long): Foo public static method constructor(p0: long): long public final static method empty(p0: long): void + public static method equals(p0: long, @org.jetbrains.annotations.Nullable p1: java.lang.Object): boolean public final static method extension(p0: long, @org.jetbrains.annotations.NotNull p1: java.lang.Object, @org.jetbrains.annotations.NotNull p2: java.lang.String): void + public static method hashCode(p0: long): int public final static method param(p0: long, p1: double): void + public static @org.jetbrains.annotations.NotNull method toString(p0: long): java.lang.String } @kotlin.Metadata @@ -12,8 +15,11 @@ public final class Foo { private final field l: long public method (p0: long): void public final method empty(): void + public method equals(p0: java.lang.Object): boolean public final method extension(@org.jetbrains.annotations.NotNull p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: java.lang.String): void public final method getL(): long + public method hashCode(): int public final method param(p0: double): void + public method toString(): java.lang.String public final method unbox(): long } diff --git a/compiler/testData/codegen/bytecodeText/inlineClasses/asCastForInlineClass.kt b/compiler/testData/codegen/bytecodeText/inlineClasses/asCastForInlineClass.kt index 1c4c92166d1..9a513dcf234 100644 --- a/compiler/testData/codegen/bytecodeText/inlineClasses/asCastForInlineClass.kt +++ b/compiler/testData/codegen/bytecodeText/inlineClasses/asCastForInlineClass.kt @@ -1,7 +1,11 @@ // !LANGUAGE: +InlineClasses +// FILE: utils.kt + inline class UInt(val u: Int) +// FILE: test.kt + fun test(a1: Any, a2: UInt?, a3: Any?, a4: Any?) { val b1 = a1 as UInt // checkcast, unbox val b2 = a2 as UInt // unbox @@ -9,6 +13,7 @@ fun test(a1: Any, a2: UInt?, a3: Any?, a4: Any?) { val b4 = a4 as? UInt // instanceof, checkcast } +// @TestKt.class: // 3 CHECKCAST UInt // 2 INVOKEVIRTUAL UInt.unbox diff --git a/compiler/testData/codegen/bytecodeText/inlineClasses/boxInlineClassInsideElvisWithNullConstant.kt b/compiler/testData/codegen/bytecodeText/inlineClasses/boxInlineClassInsideElvisWithNullConstant.kt index f69719c6c5d..f9d70ee3ac8 100644 --- a/compiler/testData/codegen/bytecodeText/inlineClasses/boxInlineClassInsideElvisWithNullConstant.kt +++ b/compiler/testData/codegen/bytecodeText/inlineClasses/boxInlineClassInsideElvisWithNullConstant.kt @@ -1,13 +1,17 @@ // !LANGUAGE: +InlineClasses +// FILE: utils.kt + inline class UInt(private val data: Int) +// FILE: test.kt + fun f() { val unull = UInt(1) ?: null } +// @TestKt.class: // 0 INVOKESTATIC UInt\$Erased.box // 0 INVOKEVIRTUAL UInt.unbox - // 0 valueOf // 0 intValue \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/inlineClasses/boxInlineClassesOnPassingToVarargs.kt b/compiler/testData/codegen/bytecodeText/inlineClasses/boxInlineClassesOnPassingToVarargs.kt index dc1c07d587b..99ca300e9bd 100644 --- a/compiler/testData/codegen/bytecodeText/inlineClasses/boxInlineClassesOnPassingToVarargs.kt +++ b/compiler/testData/codegen/bytecodeText/inlineClasses/boxInlineClassesOnPassingToVarargs.kt @@ -1,17 +1,21 @@ // !LANGUAGE: +InlineClasses +// FILE: utils.kt + inline class UInt(val u: Int) fun takeVarargs(vararg e: T) {} +// FILE: test.kt + fun test(u1: UInt, u2: UInt, u3: UInt?) { takeVarargs(u1, u2) // 2 box takeVarargs(u3) takeVarargs(u1, u3) // box } +// @TestKt.class: // 3 INVOKESTATIC UInt\$Erased.box // 0 INVOKEVIRTUAL UInt.unbox - // 0 valueOf // 0 intValue \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/inlineClasses/boxResultAfterConstructorCall.kt b/compiler/testData/codegen/bytecodeText/inlineClasses/boxResultAfterConstructorCall.kt index 34ac5df74a6..44cdee6cc24 100644 --- a/compiler/testData/codegen/bytecodeText/inlineClasses/boxResultAfterConstructorCall.kt +++ b/compiler/testData/codegen/bytecodeText/inlineClasses/boxResultAfterConstructorCall.kt @@ -1,8 +1,12 @@ // !LANGUAGE: +InlineClasses +// FILE: utils.kt + inline class AsInt(val value: Int) inline class AsAny(val value: Any) +// FILE: test.kt + fun takeAny(a: Any) {} fun test() { @@ -10,6 +14,7 @@ fun test() { takeAny(AsAny(123)) // box int, box inline class } +// @TestKt.class: // 1 INVOKESTATIC AsInt\$Erased.box // 0 INVOKEVIRTUAL AsInt.unbox diff --git a/compiler/testData/codegen/bytecodeText/inlineClasses/boxResultInlineClassOfConstructorCall.kt b/compiler/testData/codegen/bytecodeText/inlineClasses/boxResultInlineClassOfConstructorCall.kt index ae6541870e9..3d701334db9 100644 --- a/compiler/testData/codegen/bytecodeText/inlineClasses/boxResultInlineClassOfConstructorCall.kt +++ b/compiler/testData/codegen/bytecodeText/inlineClasses/boxResultInlineClassOfConstructorCall.kt @@ -1,7 +1,11 @@ // !LANGUAGE: +InlineClasses +// FILE: utils.kt + inline class Result(val a: Any?) +// FILE: test.kt + fun test() { val a = Result(1) // valueOf val b = Result("sample") @@ -10,6 +14,7 @@ fun test() { val d = Result>(Result(1)) // valueOf } +// @TestKt.class: // 0 INVOKESTATIC Result\$Erased.box // 0 INVOKEVIRTUAL Result.unbox diff --git a/compiler/testData/codegen/bytecodeText/inlineClasses/boxUnboxInlineClassFromMethodReturnType.kt b/compiler/testData/codegen/bytecodeText/inlineClasses/boxUnboxInlineClassFromMethodReturnType.kt index 4cab3f88177..8a5f8c29ee4 100644 --- a/compiler/testData/codegen/bytecodeText/inlineClasses/boxUnboxInlineClassFromMethodReturnType.kt +++ b/compiler/testData/codegen/bytecodeText/inlineClasses/boxUnboxInlineClassFromMethodReturnType.kt @@ -1,5 +1,7 @@ // !LANGUAGE: +InlineClasses +// FILE: utils.kt + inline class Foo(val a: Int) { fun member(): String = "" } @@ -9,6 +11,7 @@ fun T.idExtension(): T = this fun Foo.extension() {} +// FILE: test.kt fun test(f: Foo) { id(f) // box @@ -21,8 +24,8 @@ fun test(f: Foo) { val b = id(f).idExtension() // box unbox } +// @TestKt.class: // 6 INVOKESTATIC Foo\$Erased.box // 4 INVOKEVIRTUAL Foo.unbox - // 0 valueOf // 0 intValue \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/inlineClasses/boxUnboxInsideLambdaAsLastExpression.kt b/compiler/testData/codegen/bytecodeText/inlineClasses/boxUnboxInsideLambdaAsLastExpression.kt index ed323f28147..bc2bcdedd5d 100644 --- a/compiler/testData/codegen/bytecodeText/inlineClasses/boxUnboxInsideLambdaAsLastExpression.kt +++ b/compiler/testData/codegen/bytecodeText/inlineClasses/boxUnboxInsideLambdaAsLastExpression.kt @@ -1,7 +1,11 @@ // !LANGUAGE: +InlineClasses +// FILE: utils.kt + inline class UInt(private val u: Int) +// FILE: test.kt + fun test(x: UInt?, y: UInt) { val a = run { x!! @@ -12,6 +16,7 @@ fun test(x: UInt?, y: UInt) { } } +// @TestKt.class: // 0 INVOKESTATIC UInt\$Erased.box // 1 INVOKEVIRTUAL UInt.unbox diff --git a/compiler/testData/codegen/bytecodeText/inlineClasses/boxUnboxOfInlineClassesWithFunctionalTypes.kt b/compiler/testData/codegen/bytecodeText/inlineClasses/boxUnboxOfInlineClassesWithFunctionalTypes.kt index 14a2233f3a3..2c6d8e263c4 100644 --- a/compiler/testData/codegen/bytecodeText/inlineClasses/boxUnboxOfInlineClassesWithFunctionalTypes.kt +++ b/compiler/testData/codegen/bytecodeText/inlineClasses/boxUnboxOfInlineClassesWithFunctionalTypes.kt @@ -16,11 +16,12 @@ fun test() { } // unbox ULong } +// @TestKt.class: // 1 INVOKESTATIC UInt\$Erased.box -// 1 INVOKEVIRTUAL UInt.unbox +// 2 INVOKEVIRTUAL UInt.unbox // 1 INVOKESTATIC ULong\$Erased.box -// 1 INVOKEVIRTUAL ULong.unbox +// 2 INVOKEVIRTUAL ULong.unbox // 0 valueOf // 0 intValue diff --git a/compiler/testData/codegen/bytecodeText/inlineClasses/boxUnboxOnInlinedParameters.kt b/compiler/testData/codegen/bytecodeText/inlineClasses/boxUnboxOnInlinedParameters.kt index fa778777dc4..d21251915af 100644 --- a/compiler/testData/codegen/bytecodeText/inlineClasses/boxUnboxOnInlinedParameters.kt +++ b/compiler/testData/codegen/bytecodeText/inlineClasses/boxUnboxOnInlinedParameters.kt @@ -1,7 +1,11 @@ // !LANGUAGE: +InlineClasses +// FILE: utils.kt + inline class Foo(val a: Int) +// FILE: test.kt + fun id(x: T): T = x inline fun inlinedId(x: T): T = x @@ -18,8 +22,8 @@ fun test(f: Foo) { val b = inlinedId(f).inlinedIdExtension() } +// @TestKt.class: // 2 INVOKESTATIC Foo\$Erased.box // 1 INVOKEVIRTUAL Foo.unbox - // 0 valueOf // 0 intValue \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/inlineClasses/boxingForNonLocalAndLabeledReturnsOfInlineClasses.kt b/compiler/testData/codegen/bytecodeText/inlineClasses/boxingForNonLocalAndLabeledReturnsOfInlineClasses.kt index d3e7558495c..2fd46f03edf 100644 --- a/compiler/testData/codegen/bytecodeText/inlineClasses/boxingForNonLocalAndLabeledReturnsOfInlineClasses.kt +++ b/compiler/testData/codegen/bytecodeText/inlineClasses/boxingForNonLocalAndLabeledReturnsOfInlineClasses.kt @@ -1,7 +1,11 @@ // !LANGUAGE: +InlineClasses +// FILE: utils.kt + inline class ULong(val l: Long) +// FILE: test.kt + fun nonLocal(): ULong? { val u = ULong(0) @@ -22,6 +26,7 @@ fun labeled(): ULong? { } } +// @TestKt.class: // 2 INVOKESTATIC ULong\$Erased.box // 0 INVOKEVIRTUAL ULong.unbox diff --git a/compiler/testData/codegen/bytecodeText/inlineClasses/callMemberMethodsInsideInlineClass.kt b/compiler/testData/codegen/bytecodeText/inlineClasses/callMemberMethodsInsideInlineClass.kt index 1877ca24a7e..5c2780010fb 100644 --- a/compiler/testData/codegen/bytecodeText/inlineClasses/callMemberMethodsInsideInlineClass.kt +++ b/compiler/testData/codegen/bytecodeText/inlineClasses/callMemberMethodsInsideInlineClass.kt @@ -15,4 +15,4 @@ inline class Foo(val x: Int) { // 2 INVOKESTATIC Foo\$Erased.empty \(I\)V // 2 INVOKESTATIC Foo\$Erased.withParam \(ILjava/lang/String;\)V // 2 INVOKESTATIC Foo\$Erased.withInlineClassParam \(II\)V -// 0 INVOKEVIRTUAL \ No newline at end of file +// 5 INVOKEVIRTUAL \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/inlineClasses/inlineClassBoxingUnboxingInsideInlinedLambda.kt b/compiler/testData/codegen/bytecodeText/inlineClasses/inlineClassBoxingUnboxingInsideInlinedLambda.kt index d0d0dd23a77..9f2d0c2a7a9 100644 --- a/compiler/testData/codegen/bytecodeText/inlineClasses/inlineClassBoxingUnboxingInsideInlinedLambda.kt +++ b/compiler/testData/codegen/bytecodeText/inlineClasses/inlineClassBoxingUnboxingInsideInlinedLambda.kt @@ -1,7 +1,11 @@ // !LANGUAGE: +InlineClasses +// FILE: utils.kt + inline class UInt(val value: Int) +// FILE: test.kt + fun test(x: UInt?) { x?.myLet { // unbox takeUInt(it) @@ -24,6 +28,7 @@ fun takeNullableUInt(y: UInt?) {} inline fun T.myLet(f: (T) -> Unit) = f(this) +// @TestKt.class: // 1 INVOKESTATIC UInt\$Erased.box // 5 INVOKEVIRTUAL UInt.unbox diff --git a/compiler/testData/codegen/bytecodeText/inlineClasses/inlineClassesUnboxingAfterAssertionOperator.kt b/compiler/testData/codegen/bytecodeText/inlineClasses/inlineClassesUnboxingAfterAssertionOperator.kt index d73dafcb88e..50338ee9958 100644 --- a/compiler/testData/codegen/bytecodeText/inlineClasses/inlineClassesUnboxingAfterAssertionOperator.kt +++ b/compiler/testData/codegen/bytecodeText/inlineClasses/inlineClassesUnboxingAfterAssertionOperator.kt @@ -1,5 +1,7 @@ // !LANGUAGE: +InlineClasses +// FILE: utils.kt + inline class WithPrimitive(val a: Int) fun takeWithPrimitive(a: WithPrimitive) {} @@ -9,6 +11,8 @@ fun takeWithReference(a: WithReference) {} inline class WithNullableReference(val a: Any?) fun takeWithNullableReference(a: WithNullableReference) {} +// FILE: test.kt + fun foo(a: WithPrimitive?, b: WithPrimitive) { takeWithPrimitive(a!!) // unbox takeWithPrimitive(a) // unbox @@ -28,6 +32,7 @@ fun baz(a: WithNullableReference?, b: WithNullableReference) { takeWithNullableReference(b!!) } +// @TestKt.class: // 2 INVOKEVIRTUAL WithPrimitive\.unbox // 0 INVOKEVIRTUAL WithReference\.unbox // 3 INVOKEVIRTUAL WithNullableReference\.unbox diff --git a/compiler/testData/codegen/bytecodeText/inlineClasses/isCheckForInlineClass.kt b/compiler/testData/codegen/bytecodeText/inlineClasses/isCheckForInlineClass.kt index 005c4ae2bb9..449cf6bd3b4 100644 --- a/compiler/testData/codegen/bytecodeText/inlineClasses/isCheckForInlineClass.kt +++ b/compiler/testData/codegen/bytecodeText/inlineClasses/isCheckForInlineClass.kt @@ -1,9 +1,13 @@ // !LANGUAGE: +InlineClasses +// FILE: utils.kt + inline class UInt(val u: Int) { fun member() {} } +// FILE: test.kt + fun UInt?.extension() {} fun test(a: Any, b: Any?) { @@ -16,6 +20,7 @@ fun test(a: Any, b: Any?) { } } +// @TestKt.class: // 2 INSTANCEOF UInt // 2 CHECKCAST UInt diff --git a/compiler/testData/codegen/bytecodeText/inlineClasses/passInlineClassesWithSpreadOperatorToVarargs.kt b/compiler/testData/codegen/bytecodeText/inlineClasses/passInlineClassesWithSpreadOperatorToVarargs.kt index d3d83abdfff..88e93276f24 100644 --- a/compiler/testData/codegen/bytecodeText/inlineClasses/passInlineClassesWithSpreadOperatorToVarargs.kt +++ b/compiler/testData/codegen/bytecodeText/inlineClasses/passInlineClassesWithSpreadOperatorToVarargs.kt @@ -1,7 +1,11 @@ // !LANGUAGE: +InlineClasses +// FILE: utils.kt + inline class UInt(val u: Int) +// FILE: test.kt + fun takeVarargs(vararg e: T) {} fun test(u1: UInt, u2: UInt, us: Array) { @@ -9,6 +13,7 @@ fun test(u1: UInt, u2: UInt, us: Array) { takeVarargs(u1, u2, *us) // 2 box + ... } +// @TestKt.class: // 2 INVOKESTATIC UInt\$Erased.box // 0 INVOKEVIRTUAL UInt.unbox diff --git a/compiler/testData/codegen/bytecodeText/inlineClasses/skipCallToUnderlyingValueOfInlineClass.kt b/compiler/testData/codegen/bytecodeText/inlineClasses/skipCallToUnderlyingValueOfInlineClass.kt index 679931f4fa6..644a4d128e9 100644 --- a/compiler/testData/codegen/bytecodeText/inlineClasses/skipCallToUnderlyingValueOfInlineClass.kt +++ b/compiler/testData/codegen/bytecodeText/inlineClasses/skipCallToUnderlyingValueOfInlineClass.kt @@ -1,7 +1,11 @@ // !LANGUAGE: +InlineClasses +// FILE: utils.kt + inline class UInt(val value: Int) +// FILE: test.kt + fun test(u1: UInt, u2: UInt) { val a = u1.value @@ -9,6 +13,7 @@ fun test(u1: UInt, u2: UInt) { val c = u1.value + u2.value } +// @TestKt.class: // 0 INVOKESTATIC UInt\$Erased.getValue // 0 INVOKESTATIC UInt\$Erased.box // 0 INVOKEVIRTUAL UInt.unbox diff --git a/compiler/testData/codegen/bytecodeText/inlineClasses/uIntArrayIteratorWithoutBoxing.kt b/compiler/testData/codegen/bytecodeText/inlineClasses/uIntArrayIteratorWithoutBoxing.kt index a165ea93685..1f4b339dbb6 100644 --- a/compiler/testData/codegen/bytecodeText/inlineClasses/uIntArrayIteratorWithoutBoxing.kt +++ b/compiler/testData/codegen/bytecodeText/inlineClasses/uIntArrayIteratorWithoutBoxing.kt @@ -28,7 +28,7 @@ fun test() { fun takeUInt(u: UInt) {} // 1 INVOKESTATIC UInt\$Erased.box -// 0 INVOKEVIRTUAL UInt.unbox +// 1 INVOKEVIRTUAL UInt.unbox // 0 INVOKEVIRTUAL UIntIterator.iterator // 1 INVOKESTATIC kotlin/jvm/internal/ArrayIteratorsKt.iterator diff --git a/compiler/testData/codegen/bytecodeText/inlineClasses/uIntArraySwapBoxing.kt b/compiler/testData/codegen/bytecodeText/inlineClasses/uIntArraySwapBoxing.kt index 3a866468394..395b1f546e2 100644 --- a/compiler/testData/codegen/bytecodeText/inlineClasses/uIntArraySwapBoxing.kt +++ b/compiler/testData/codegen/bytecodeText/inlineClasses/uIntArraySwapBoxing.kt @@ -1,5 +1,7 @@ // !LANGUAGE: +InlineClasses +// FILE: utils.kt + inline class UInt(private val value: Int) { fun asInt() = value } @@ -12,12 +14,14 @@ inline class UIntArray(private val intArray: IntArray) { } } +// FILE: test.kt + fun UIntArray.swap(i: Int, j: Int) { this[j] = this[i].also { this[i] = this[j] } } +// @TestKt.class: // 0 INVOKEVIRTUAL UInt.unbox // 0 INVOKESTATIC UInt\$Erased.box - // 0 intValue // 0 valueOf \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/inlineClasses/unboxInlineClassAfterElvis.kt b/compiler/testData/codegen/bytecodeText/inlineClasses/unboxInlineClassAfterElvis.kt index 7ac92925988..fe15ea8d553 100644 --- a/compiler/testData/codegen/bytecodeText/inlineClasses/unboxInlineClassAfterElvis.kt +++ b/compiler/testData/codegen/bytecodeText/inlineClasses/unboxInlineClassAfterElvis.kt @@ -1,12 +1,17 @@ // !LANGUAGE: +InlineClasses +// FILE: utils.kt + inline class UInt(private val u: Int) +// FILE: test.kt + fun test(x: UInt?, y: UInt) { val a = x ?: y // unbox val b = x ?: x!! // unbox unbox } +// @TestKt.class: // 0 INVOKESTATIC UInt\$Erased.box // 3 INVOKEVIRTUAL UInt.unbox diff --git a/compiler/testData/codegen/bytecodeText/inlineClasses/unboxInlineClassAfterSafeCall.kt b/compiler/testData/codegen/bytecodeText/inlineClasses/unboxInlineClassAfterSafeCall.kt index cef708b126b..8a5bcfb523d 100644 --- a/compiler/testData/codegen/bytecodeText/inlineClasses/unboxInlineClassAfterSafeCall.kt +++ b/compiler/testData/codegen/bytecodeText/inlineClasses/unboxInlineClassAfterSafeCall.kt @@ -1,9 +1,13 @@ // !LANGUAGE: +InlineClasses +// FILE: utils.kt + inline class Foo(val x: Int) { fun member() {} } +// FILE: test.kt + fun Foo.extension() {} fun T.genericExtension() {} @@ -13,6 +17,7 @@ fun test(f: Foo?) { f?.genericExtension() } +// @TestKt.class: // 0 INVOKESTATIC Foo\$Erased.box // 2 INVOKEVIRTUAL Foo.unbox diff --git a/compiler/testData/codegen/bytecodeText/inlineClasses/unboxInlineClassFromParameterizedType.kt b/compiler/testData/codegen/bytecodeText/inlineClasses/unboxInlineClassFromParameterizedType.kt index 70ac452df29..85ffcee6e69 100644 --- a/compiler/testData/codegen/bytecodeText/inlineClasses/unboxInlineClassFromParameterizedType.kt +++ b/compiler/testData/codegen/bytecodeText/inlineClasses/unboxInlineClassFromParameterizedType.kt @@ -1,9 +1,13 @@ // !LANGUAGE: +InlineClasses +// FILE: utils.kt + inline class Result(val a: Any?) { fun typed(): T = a as T } +// FILE: test.kt + fun materialize(): K = TODO() fun test(asInt: Result, asString: Result, asResult: Result>) { @@ -21,6 +25,7 @@ fun test(asInt: Result, asString: Result, asResult: Result