JVM JVM_IR hide sealed class constructors
This commit is contained in:
@@ -19,7 +19,6 @@ import org.jetbrains.kotlin.resolve.BindingContext;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
|
||||
import org.jetbrains.kotlin.resolve.InlineClassesUtilsKt;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
||||
import org.jetbrains.kotlin.resolve.jvm.InlineClassManglingRulesKt;
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin;
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt;
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind;
|
||||
@@ -118,8 +117,9 @@ public class ConstructorCodegen {
|
||||
}
|
||||
|
||||
private void registerAccessorForHiddenConstructorIfNeeded(ClassConstructorDescriptor descriptor) {
|
||||
if (!InlineClassManglingRulesKt.shouldHideConstructorDueToInlineClassTypeValueParameters(descriptor)) return;
|
||||
context.getAccessor(descriptor, AccessorKind.NORMAL, null, null);
|
||||
if (DescriptorAsmUtil.isHiddenConstructor(descriptor)) {
|
||||
context.getAccessor(descriptor, AccessorKind.NORMAL, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
public void generateSecondaryConstructor(
|
||||
@@ -371,11 +371,13 @@ public class ConstructorCodegen {
|
||||
JvmMethodParameterKind delegatingKind = delegatingParameters.get(index).getKind();
|
||||
if (delegatingKind == JvmMethodParameterKind.VALUE) {
|
||||
assert index == parameters.size() || parameters.get(index).getKind() == JvmMethodParameterKind.VALUE:
|
||||
"Delegating constructor has not enough implicit parameters";
|
||||
"Delegating constructor has not enough implicit parameters: " + delegatingConstructor;
|
||||
break;
|
||||
}
|
||||
assert index < parameters.size() && parameters.get(index).getKind() == delegatingKind :
|
||||
"Constructors of the same class should have the same set of implicit arguments";
|
||||
if (index >= parameters.size() || parameters.get(index).getKind() != delegatingKind) {
|
||||
throw new AssertionError(
|
||||
"Constructors of the same class should have the same set of implicit arguments: " + delegatingConstructor);
|
||||
}
|
||||
JvmMethodParameterSignature parameter = parameters.get(index);
|
||||
|
||||
iv.load(offset, parameter.getAsmType());
|
||||
@@ -383,7 +385,7 @@ public class ConstructorCodegen {
|
||||
}
|
||||
|
||||
assert index == parameters.size() || parameters.get(index).getKind() == JvmMethodParameterKind.VALUE :
|
||||
"Delegating constructor has not enough parameters";
|
||||
"Delegating constructor has not enough parameters: " + delegatingConstructor;
|
||||
|
||||
return new CallBasedArgumentGenerator(codegen, codegen.defaultCallGenerator, delegatingConstructor.getValueParameters(),
|
||||
delegatingCallable.getValueParameterTypes());
|
||||
|
||||
@@ -61,7 +61,8 @@ import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isJvmInterface;
|
||||
import static org.jetbrains.kotlin.resolve.DescriptorUtils.*;
|
||||
import static org.jetbrains.kotlin.resolve.inline.InlineOnlyKt.isInlineOnlyPrivateInBytecode;
|
||||
import static org.jetbrains.kotlin.resolve.inline.InlineOnlyKt.isInlineWithReified;
|
||||
import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.*;
|
||||
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.kotlin.resolve.jvm.annotations.JvmAnnotationUtilKt.hasJvmSyntheticAnnotation;
|
||||
import static org.jetbrains.kotlin.types.TypeUtils.isNullableType;
|
||||
import static org.jetbrains.org.objectweb.asm.Opcodes.*;
|
||||
@@ -368,6 +369,18 @@ public class DescriptorAsmUtil {
|
||||
return ACC_PRIVATE;
|
||||
}
|
||||
|
||||
// Sealed class constructors should be ACC_PRIVATE.
|
||||
// In 1.4 and before, sealed class constructors had PRIVATE visibility, and were represented as private methods in bytecode.
|
||||
// In 1.5 (+AllowSealedInheritorsInDifferentFilesOfSamePackage), sealed class constructors became INTERNAL,
|
||||
// but still should be represented as private methods in bytecode in order to prevent inheriting from sealed classes on JVM.
|
||||
if (memberDescriptor instanceof ConstructorDescriptor &&
|
||||
!(memberDescriptor instanceof AccessorForConstructorDescriptor) &&
|
||||
isSealedClass(((ConstructorDescriptor) memberDescriptor).getConstructedClass()) &&
|
||||
memberDescriptor.getVisibility() != DescriptorVisibilities.PUBLIC
|
||||
) {
|
||||
return ACC_PRIVATE;
|
||||
}
|
||||
|
||||
if (isInlineOnlyPrivateInBytecode(memberDescriptor)) {
|
||||
return ACC_PRIVATE;
|
||||
}
|
||||
@@ -893,4 +906,19 @@ public class DescriptorAsmUtil {
|
||||
//Trait always should have this descriptor
|
||||
return kind != OwnerKind.DEFAULT_IMPLS && isStaticMethod(kind, descriptor) ? 0 : 1;
|
||||
}
|
||||
|
||||
public static boolean isHiddenConstructor(FunctionDescriptor descriptor) {
|
||||
if (!(descriptor instanceof ClassConstructorDescriptor)) return false;
|
||||
|
||||
ClassConstructorDescriptor classConstructorDescriptor = (ClassConstructorDescriptor) descriptor;
|
||||
if (InlineClassManglingRulesKt.shouldHideConstructorDueToInlineClassTypeValueParameters(descriptor)) {
|
||||
return true;
|
||||
}
|
||||
if (isSealedClass(classConstructorDescriptor.getConstructedClass()) &&
|
||||
classConstructorDescriptor.getVisibility() != DescriptorVisibilities.PUBLIC
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2523,21 +2523,39 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
// $default method is not private, so you need no accessor to call it
|
||||
return descriptor;
|
||||
}
|
||||
else if (InlineClassManglingRulesKt.shouldHideConstructorDueToInlineClassTypeValueParameters(descriptor.getOriginal())) {
|
||||
// Constructors with inline class type value parameters should always be called using an accessor.
|
||||
// NB this will require accessors even if the constructor itself is in a different module.
|
||||
return new AccessorForConstructorDescriptor(
|
||||
(ClassConstructorDescriptor) descriptor.getOriginal(),
|
||||
descriptor.getContainingDeclaration(),
|
||||
getSuperCallTarget(resolvedCall.getCall()),
|
||||
AccessorKind.NORMAL
|
||||
);
|
||||
else if (shouldForceAccessorForConstructor(descriptor.getOriginal())) {
|
||||
return createAccessorForHiddenConstructor(resolvedCall, descriptor);
|
||||
}
|
||||
else {
|
||||
return context.accessibleDescriptor(descriptor, getSuperCallTarget(resolvedCall.getCall()));
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldForceAccessorForConstructor(FunctionDescriptor descriptor) {
|
||||
// Force using accessors on hidden constructors only
|
||||
if (!isHiddenConstructor(descriptor)) {
|
||||
return false;
|
||||
}
|
||||
// Don't use accessor when calling hidden constructor from the same class.
|
||||
if (descriptor.getContainingDeclaration() == context.getContextDescriptor().getContainingDeclaration()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private AccessorForConstructorDescriptor createAccessorForHiddenConstructor(
|
||||
@NotNull ResolvedCall<?> resolvedCall,
|
||||
FunctionDescriptor descriptor
|
||||
) {
|
||||
return new AccessorForConstructorDescriptor(
|
||||
(ClassConstructorDescriptor) descriptor.getOriginal(),
|
||||
descriptor.getContainingDeclaration(),
|
||||
getSuperCallTarget(resolvedCall.getCall()),
|
||||
AccessorKind.NORMAL
|
||||
);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public StackValue invokeFunction(@NotNull ResolvedCall<?> resolvedCall, @NotNull StackValue receiver) {
|
||||
return invokeFunction(resolvedCall.getCall(), resolvedCall, receiver);
|
||||
|
||||
Reference in New Issue
Block a user