Generate function from Any for inline classes same as for data classes
#KT-24873 Fixed #KT-25293 Fixed #KT-25299 Fixed
This commit is contained in:
@@ -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() {
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
+113
-28
@@ -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<? extends PropertyDescriptor> 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<? extends PropertyDescriptor> 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<? extends PropertyDescriptor> 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
+51
@@ -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"
|
||||
}
|
||||
Vendored
+6
@@ -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 <clinit>(): void
|
||||
public method <init>(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
|
||||
}
|
||||
|
||||
Vendored
+6
@@ -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 <init>(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
|
||||
}
|
||||
|
||||
+6
@@ -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 <init>(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
|
||||
}
|
||||
|
||||
Vendored
+6
@@ -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 <init>(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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Vendored
+5
-1
@@ -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
|
||||
+5
-1
@@ -1,17 +1,21 @@
|
||||
// !LANGUAGE: +InlineClasses
|
||||
|
||||
// FILE: utils.kt
|
||||
|
||||
inline class UInt(val u: Int)
|
||||
|
||||
fun <T> 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
|
||||
+5
@@ -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
|
||||
|
||||
|
||||
Vendored
+5
@@ -1,7 +1,11 @@
|
||||
// !LANGUAGE: +InlineClasses
|
||||
|
||||
// FILE: utils.kt
|
||||
|
||||
inline class Result<T>(val a: Any?)
|
||||
|
||||
// FILE: test.kt
|
||||
|
||||
fun test() {
|
||||
val a = Result<Int>(1) // valueOf
|
||||
val b = Result<String>("sample")
|
||||
@@ -10,6 +14,7 @@ fun test() {
|
||||
val d = Result<Result<Int>>(Result<Int>(1)) // valueOf
|
||||
}
|
||||
|
||||
// @TestKt.class:
|
||||
// 0 INVOKESTATIC Result\$Erased.box
|
||||
// 0 INVOKEVIRTUAL Result.unbox
|
||||
|
||||
|
||||
Vendored
+4
-1
@@ -1,5 +1,7 @@
|
||||
// !LANGUAGE: +InlineClasses
|
||||
|
||||
// FILE: utils.kt
|
||||
|
||||
inline class Foo(val a: Int) {
|
||||
fun member(): String = ""
|
||||
}
|
||||
@@ -9,6 +11,7 @@ fun <T> 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
|
||||
Vendored
+5
@@ -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
|
||||
|
||||
|
||||
Vendored
+3
-2
@@ -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
|
||||
|
||||
+5
-1
@@ -1,7 +1,11 @@
|
||||
// !LANGUAGE: +InlineClasses
|
||||
|
||||
// FILE: utils.kt
|
||||
|
||||
inline class Foo(val a: Int)
|
||||
|
||||
// FILE: test.kt
|
||||
|
||||
fun <T> id(x: T): T = x
|
||||
inline fun <T> 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
|
||||
+5
@@ -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
|
||||
|
||||
|
||||
+1
-1
@@ -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
|
||||
// 5 INVOKEVIRTUAL
|
||||
compiler/testData/codegen/bytecodeText/inlineClasses/inlineClassBoxingUnboxingInsideInlinedLambda.kt
Vendored
+5
@@ -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> T.myLet(f: (T) -> Unit) = f(this)
|
||||
|
||||
// @TestKt.class:
|
||||
// 1 INVOKESTATIC UInt\$Erased.box
|
||||
// 5 INVOKEVIRTUAL UInt.unbox
|
||||
|
||||
|
||||
Vendored
+5
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
compiler/testData/codegen/bytecodeText/inlineClasses/passInlineClassesWithSpreadOperatorToVarargs.kt
Vendored
+5
@@ -1,7 +1,11 @@
|
||||
// !LANGUAGE: +InlineClasses
|
||||
|
||||
// FILE: utils.kt
|
||||
|
||||
inline class UInt(val u: Int)
|
||||
|
||||
// FILE: test.kt
|
||||
|
||||
fun <T> takeVarargs(vararg e: T) {}
|
||||
|
||||
fun test(u1: UInt, u2: UInt, us: Array<UInt>) {
|
||||
@@ -9,6 +13,7 @@ fun test(u1: UInt, u2: UInt, us: Array<UInt>) {
|
||||
takeVarargs(u1, u2, *us) // 2 box + ...
|
||||
}
|
||||
|
||||
// @TestKt.class:
|
||||
// 2 INVOKESTATIC UInt\$Erased.box
|
||||
// 0 INVOKEVIRTUAL UInt.unbox
|
||||
|
||||
|
||||
Vendored
+5
@@ -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
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+5
-1
@@ -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
|
||||
+5
@@ -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
|
||||
|
||||
|
||||
+5
@@ -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> T.genericExtension() {}
|
||||
|
||||
@@ -13,6 +17,7 @@ fun test(f: Foo?) {
|
||||
f?.genericExtension()
|
||||
}
|
||||
|
||||
// @TestKt.class:
|
||||
// 0 INVOKESTATIC Foo\$Erased.box
|
||||
// 2 INVOKEVIRTUAL Foo.unbox
|
||||
|
||||
|
||||
Vendored
+5
@@ -1,9 +1,13 @@
|
||||
// !LANGUAGE: +InlineClasses
|
||||
|
||||
// FILE: utils.kt
|
||||
|
||||
inline class Result<T>(val a: Any?) {
|
||||
fun typed(): T = a as T
|
||||
}
|
||||
|
||||
// FILE: test.kt
|
||||
|
||||
fun <K> materialize(): K = TODO()
|
||||
|
||||
fun test(asInt: Result<Int>, asString: Result<String>, asResult: Result<Result<Int>>) {
|
||||
@@ -21,6 +25,7 @@ fun test(asInt: Result<Int>, asString: Result<String>, asResult: Result<Result<I
|
||||
asResult.typed()
|
||||
}
|
||||
|
||||
// @TestKt.class:
|
||||
// 0 INVOKESTATIC Result\$Erased.box
|
||||
// 3 INVOKEVIRTUAL Result.unbox
|
||||
|
||||
|
||||
+5
-1
@@ -1,9 +1,13 @@
|
||||
// !LANGUAGE: +InlineClasses
|
||||
|
||||
// FILE: utils.kt
|
||||
|
||||
inline class Foo(val x: Int) {
|
||||
fun member() {}
|
||||
}
|
||||
|
||||
// FILE: test.kt
|
||||
|
||||
fun Foo?.extensionOnNullable() {}
|
||||
|
||||
fun test(f: Foo?) {
|
||||
@@ -21,8 +25,8 @@ fun test(f: Foo?) {
|
||||
}
|
||||
}
|
||||
|
||||
// @TestKt.class:
|
||||
// 0 INVOKESTATIC Foo\$Erased.box
|
||||
// 2 INVOKEVIRTUAL Foo.unbox
|
||||
|
||||
// 0 valueOf
|
||||
// 0 intValue
|
||||
Generated
+5
@@ -11298,6 +11298,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/crossinlineWithInlineClassInParameter.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("defaultFunctionsFromAnyForInlineClass.kt")
|
||||
public void testDefaultFunctionsFromAnyForInlineClass() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/defaultFunctionsFromAnyForInlineClass.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("elvisWithInlineClassAndNullConstant.kt")
|
||||
public void testElvisWithInlineClassAndNullConstant() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/elvisWithInlineClassAndNullConstant.kt");
|
||||
|
||||
+5
@@ -11298,6 +11298,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/crossinlineWithInlineClassInParameter.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("defaultFunctionsFromAnyForInlineClass.kt")
|
||||
public void testDefaultFunctionsFromAnyForInlineClass() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/defaultFunctionsFromAnyForInlineClass.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("elvisWithInlineClassAndNullConstant.kt")
|
||||
public void testElvisWithInlineClassAndNullConstant() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/elvisWithInlineClassAndNullConstant.kt");
|
||||
|
||||
+5
@@ -11298,6 +11298,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/crossinlineWithInlineClassInParameter.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("defaultFunctionsFromAnyForInlineClass.kt")
|
||||
public void testDefaultFunctionsFromAnyForInlineClass() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/defaultFunctionsFromAnyForInlineClass.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("elvisWithInlineClassAndNullConstant.kt")
|
||||
public void testElvisWithInlineClassAndNullConstant() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/elvisWithInlineClassAndNullConstant.kt");
|
||||
|
||||
+5
@@ -9933,6 +9933,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/crossinlineWithInlineClassInParameter.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("defaultFunctionsFromAnyForInlineClass.kt")
|
||||
public void testDefaultFunctionsFromAnyForInlineClass() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/defaultFunctionsFromAnyForInlineClass.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("elvisWithInlineClassAndNullConstant.kt")
|
||||
public void testElvisWithInlineClassAndNullConstant() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/elvisWithInlineClassAndNullConstant.kt");
|
||||
|
||||
+5
@@ -10928,6 +10928,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/crossinlineWithInlineClassInParameter.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("defaultFunctionsFromAnyForInlineClass.kt")
|
||||
public void testDefaultFunctionsFromAnyForInlineClass() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/defaultFunctionsFromAnyForInlineClass.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("elvisWithInlineClassAndNullConstant.kt")
|
||||
public void testElvisWithInlineClassAndNullConstant() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/elvisWithInlineClassAndNullConstant.kt");
|
||||
|
||||
Reference in New Issue
Block a user