Value classes: treat @JvmInline value classes as inline classes

Report error on value classes without @JvmInline annotation.
Do not check for @JvmInline annotation in value classes since
it breaks reflection.
This commit is contained in:
Ilmir Usmanov
2020-11-19 02:20:37 +01:00
parent 6c68660ffd
commit 92f1681de0
100 changed files with 2668 additions and 53 deletions
@@ -267,7 +267,7 @@ class DefaultParameterValueSubstitutor(val state: GenerationState) {
if (classDescriptor.kind != ClassKind.CLASS) return false
if (classOrObject.isLocal) return false
if (classDescriptor.isInline) return false
if (classDescriptor.isInlineClass()) return false
if (shouldHideConstructorDueToInlineClassTypeValueParameters(constructorDescriptor)) return false
if (CodegenBinding.canHaveOuter(state.bindingContext, classDescriptor)) return false
@@ -216,7 +216,7 @@ public class DescriptorAsmUtil {
private static boolean isInlineClassWrapperConstructor(@NotNull FunctionDescriptor functionDescriptor, @Nullable OwnerKind kind) {
if (!(functionDescriptor instanceof ConstructorDescriptor)) return false;
ClassDescriptor classDescriptor = ((ConstructorDescriptor) functionDescriptor).getConstructedClass();
return classDescriptor.isInline() && kind == OwnerKind.IMPLEMENTATION;
return InlineClassesUtilsKt.isInlineClass(classDescriptor) && kind == OwnerKind.IMPLEMENTATION;
}
public static int getCommonCallableFlags(FunctionDescriptor functionDescriptor, @NotNull GenerationState state) {
@@ -559,7 +559,7 @@ public class DescriptorAsmUtil {
if (receiverKotlinType.isMarkedNullable()) return null;
DeclarationDescriptor receiverTypeDescriptor = receiverKotlinType.getConstructor().getDeclarationDescriptor();
assert receiverTypeDescriptor instanceof ClassDescriptor && ((ClassDescriptor) receiverTypeDescriptor).isInline() :
assert receiverTypeDescriptor != null && InlineClassesUtilsKt.isInlineClass(receiverTypeDescriptor) :
"Inline class type expected: " + receiverKotlinType;
ClassDescriptor receiverClassDescriptor = (ClassDescriptor) receiverTypeDescriptor;
FunctionDescriptor toStringDescriptor = receiverClassDescriptor.getUnsubstitutedMemberScope()
@@ -1190,7 +1190,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
ClassDescriptor captureThis = closure.getCapturedOuterClassDescriptor();
if (captureThis != null) {
StackValue thisOrOuter = generateThisOrOuter(captureThis, false);
assert !isPrimitive(thisOrOuter.type) || captureThis.isInline() :
assert !isPrimitive(thisOrOuter.type) || InlineClassesUtilsKt.isInlineClass(captureThis) :
"This or outer for " + captureThis + " should be non-primitive: " + thisOrOuter.type;
callGenerator.putCapturedValueOnStack(thisOrOuter, thisOrOuter.type, paramIndex++);
}
@@ -4830,7 +4830,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
ReceiverParameterDescriptor dispatchReceiver = constructor.getDispatchReceiverParameter();
ClassDescriptor containingDeclaration = constructor.getContainingDeclaration();
if (!containingDeclaration.isInline()) {
if (!InlineClassesUtilsKt.isInlineClass(containingDeclaration)) {
v.anew(objectType);
v.dup();
}
@@ -1589,7 +1589,7 @@ public class FunctionCodegen {
// When delegating to inline class, we invoke static implementation method
// that takes inline class underlying value as 1st argument.
int toArgsShift = toClass.isInline() ? 1 : 0;
int toArgsShift = InlineClassesUtilsKt.isInlineClass(toClass) ? 1 : 0;
int reg = 1;
for (int i = 0; i < argTypes.length; ++i) {
@@ -1609,7 +1609,7 @@ public class FunctionCodegen {
if (toClass.getKind() == ClassKind.INTERFACE) {
iv.invokeinterface(internalName, delegateToMethod.getName(), delegateToMethod.getDescriptor());
}
else if (toClass.isInline()) {
else if (InlineClassesUtilsKt.isInlineClass(toClass)) {
iv.invokestatic(internalName, delegateToMethod.getName(), delegateToMethod.getDescriptor(), false);
}
else {
@@ -84,7 +84,7 @@ public class FunctionsFromAnyGeneratorImpl extends FunctionsFromAnyGenerator {
String toStringMethodDesc = getToStringDesc();
MethodVisitor mv = v.newMethod(methodOrigin, getAccess(), toStringMethodName, toStringMethodDesc, null, null);
if (!isInErasedInlineClass && classDescriptor.isInline()) {
if (!isInErasedInlineClass && InlineClassesUtilsKt.isInlineClass(classDescriptor)) {
FunctionCodegen.generateMethodInsideInlineClassWrapper(methodOrigin, function, classDescriptor, mv, typeMapper);
return;
}
@@ -161,7 +161,7 @@ public class FunctionsFromAnyGeneratorImpl extends FunctionsFromAnyGenerator {
String hashCodeMethodDesc = getHashCodeDesc();
MethodVisitor mv = v.newMethod(methodOrigin, getAccess(), hashCodeMethodName, hashCodeMethodDesc, null, null);
if (!isInErasedInlineClass && classDescriptor.isInline()) {
if (!isInErasedInlineClass && InlineClassesUtilsKt.isInlineClass(classDescriptor)) {
FunctionCodegen.generateMethodInsideInlineClassWrapper(methodOrigin, function, classDescriptor, mv, typeMapper);
return;
}
@@ -233,7 +233,7 @@ public class FunctionsFromAnyGeneratorImpl extends FunctionsFromAnyGenerator {
String equalsMethodDesc = getEqualsDesc();
MethodVisitor mv = v.newMethod(methodOrigin, getAccess(), equalsMethodName, equalsMethodDesc, null, null);
if (!isInErasedInlineClass && classDescriptor.isInline()) {
if (!isInErasedInlineClass && InlineClassesUtilsKt.isInlineClass(classDescriptor)) {
FunctionCodegen.generateMethodInsideInlineClassWrapper(methodOrigin, function, classDescriptor, mv, typeMapper);
return;
}
@@ -260,7 +260,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
@Override
protected void generateErasedInlineClassIfNeeded() {
if (!(myClass instanceof KtClass)) return;
if (!descriptor.isInline()) return;
if (!InlineClassesUtilsKt.isInlineClass(descriptor)) return;
ClassContext erasedInlineClassContext = context.intoWrapperForErasedInlineClass(descriptor, state);
new ErasedInlineClassBodyCodegen((KtClass) myClass, erasedInlineClassContext, v, state, this).generate();
@@ -269,7 +269,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
@Override
protected void generateUnboxMethodForInlineClass() {
if (!(myClass instanceof KtClass)) return;
if (!descriptor.isInline()) return;
if (!InlineClassesUtilsKt.isInlineClass(descriptor)) return;
Type ownerType = typeMapper.mapClass(descriptor);
ValueParameterDescriptor inlinedValue = InlineClassesUtilsKt.underlyingRepresentation(this.descriptor);
@@ -450,7 +450,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
try {
lookupConstructorExpressionsInClosureIfPresent();
constructorCodegen.generatePrimaryConstructor(delegationFieldsInfo, superClassAsmType);
if (!descriptor.isInline() && !(descriptor instanceof SyntheticClassOrObjectDescriptor)) {
if (!InlineClassesUtilsKt.isInlineClass(descriptor) && !(descriptor instanceof SyntheticClassOrObjectDescriptor)) {
// Synthetic classes does not have declarations for secondary constructors
for (ClassConstructorDescriptor secondaryConstructor : DescriptorUtilsKt.getSecondaryConstructors(descriptor)) {
constructorCodegen.generateSecondaryConstructor(secondaryConstructor, superClassAsmType);
@@ -552,7 +552,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
}
private void generateFunctionsFromAnyForInlineClasses() {
if (!descriptor.isInline()) return;
if (!InlineClassesUtilsKt.isInlineClass(descriptor)) return;
if (!(myClass instanceof KtClassOrObject)) return;
new FunctionsFromAnyGeneratorImpl(
(KtClassOrObject) myClass, bindingContext, descriptor, classAsmType, context, v, state
@@ -775,7 +775,8 @@ public abstract class StackValue {
) {
// Coerce 'this' for the case when it is smart cast.
// Do not coerce for other cases due to the 'protected' access issues (JVMS 7, 4.9.2 Structural Constraints).
boolean coerceType = descriptor.getKind() == ClassKind.INTERFACE || descriptor.isInline() || (castReceiver && !isSuper);
boolean coerceType = descriptor.getKind() == ClassKind.INTERFACE || InlineClassesUtilsKt.isInlineClass(descriptor) ||
(castReceiver && !isSuper);
return new ThisOuter(codegen, descriptor, isSuper, coerceType);
}
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.codegen.binding.MutableClosure;
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor;
import org.jetbrains.kotlin.resolve.InlineClassesUtilsKt;
import org.jetbrains.kotlin.resolve.jvm.AsmTypes;
import org.jetbrains.kotlin.types.SimpleType;
import org.jetbrains.org.objectweb.asm.Type;
@@ -48,7 +49,7 @@ public class ConstructorContext extends MethodContext {
ClassDescriptor capturedOuterClassDescriptor = closure != null ? closure.getCapturedOuterClassDescriptor() : null;
StackValue stackValue;
if (capturedOuterClassDescriptor != null) {
if (capturedOuterClassDescriptor.isInline()) {
if (InlineClassesUtilsKt.isInlineClass(capturedOuterClassDescriptor)) {
SimpleType outerClassKotlinType = capturedOuterClassDescriptor.getDefaultType();
Type outerClassType = kotlinTypeMapper.mapType(capturedOuterClassDescriptor);
stackValue = StackValue.local(1, outerClassType, outerClassKotlinType);
@@ -20,6 +20,7 @@ import com.intellij.openapi.util.Pair
import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.resolve.isInlineClass
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
@@ -119,7 +120,7 @@ fun getUnboxedType(boxedType: Type, state: GenerationState): Type {
fun unboxedTypeOfInlineClass(boxedType: Type, state: GenerationState): Type? {
val descriptor =
state.jvmBackendClassResolver.resolveToClassDescriptors(boxedType).singleOrNull()?.takeIf { it.isInline } ?: return null
state.jvmBackendClassResolver.resolveToClassDescriptors(boxedType).singleOrNull()?.takeIf { it.isInlineClass() } ?: return null
return state.mapInlineClass(descriptor)
}
@@ -445,7 +445,7 @@ class KotlinTypeMapper @JvmOverloads constructor(
}
}
} else {
val toInlinedErasedClass = functionParent.isInline &&
val toInlinedErasedClass = functionParent.isInlineClass() &&
(!isAccessor(functionDescriptor) || isInlineClassConstructorAccessor(functionDescriptor))
if (toInlinedErasedClass) {
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.InlineClassDescriptorResolver
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.resolve.isInlineClass
import org.jetbrains.kotlin.resolve.jvm.requiresFunctionNameManglingForParameterTypes
import org.jetbrains.kotlin.resolve.jvm.requiresFunctionNameManglingForReturnType
import org.jetbrains.kotlin.types.KotlinType
@@ -111,7 +112,7 @@ fun getManglingSuffixBasedOnKotlinSignature(
private fun getInfoForMangling(type: KotlinType): InfoForMangling? {
val descriptor = type.constructor.declarationDescriptor ?: return null
return when (descriptor) {
is ClassDescriptor -> InfoForMangling(descriptor.fqNameUnsafe, descriptor.isInline, type.isMarkedNullable)
is ClassDescriptor -> InfoForMangling(descriptor.fqNameUnsafe, descriptor.isInlineClass(), type.isMarkedNullable)
is TypeParameterDescriptor -> {
getInfoForMangling(descriptor.representativeUpperBound)
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.isInlineClass
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
@@ -93,4 +94,4 @@ fun KotlinType.removeExternalProjections(): KotlinType {
fun isInlineClassConstructorAccessor(descriptor: FunctionDescriptor): Boolean =
descriptor is AccessorForConstructorDescriptor &&
descriptor.calleeDescriptor.constructedClass.isInline
descriptor.calleeDescriptor.constructedClass.isInlineClass()