Generate toArray methods defined in classes inherited from collections as public even if they are declared with different visibility in Kotlin.
This commit is contained in:
@@ -63,6 +63,7 @@ import java.util.Set;
|
||||
|
||||
import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isBoolean;
|
||||
import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isPrimitiveClass;
|
||||
import static org.jetbrains.kotlin.codegen.CodegenUtilKt.isToArrayFromCollection;
|
||||
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isConstOrHasJvmFieldAnnotation;
|
||||
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isJvmInterface;
|
||||
import static org.jetbrains.kotlin.descriptors.annotations.AnnotationUtilKt.isInlineOnlyOrReified;
|
||||
@@ -354,6 +355,10 @@ public class AsmUtil {
|
||||
return NO_FLAG_PACKAGE_PRIVATE;
|
||||
}
|
||||
|
||||
if (isToArrayFromCollection(memberDescriptor)) {
|
||||
return ACC_PUBLIC;
|
||||
}
|
||||
|
||||
if (memberDescriptor instanceof ConstructorDescriptor && isAnonymousObject(memberDescriptor.getContainingDeclaration())) {
|
||||
return getVisibilityAccessFlagForAnonymous((ClassDescriptor) memberDescriptor.getContainingDeclaration());
|
||||
}
|
||||
|
||||
@@ -62,7 +62,6 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver;
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver;
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
|
||||
import org.jetbrains.org.objectweb.asm.FieldVisitor;
|
||||
import org.jetbrains.org.objectweb.asm.Label;
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor;
|
||||
@@ -74,6 +73,8 @@ import java.util.*;
|
||||
|
||||
import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.FQ_NAMES;
|
||||
import static org.jetbrains.kotlin.codegen.AsmUtil.*;
|
||||
import static org.jetbrains.kotlin.codegen.CodegenUtilKt.isGenericToArray;
|
||||
import static org.jetbrains.kotlin.codegen.CodegenUtilKt.isNonGenericToArray;
|
||||
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.*;
|
||||
import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.enumEntryNeedSubclass;
|
||||
import static org.jetbrains.kotlin.resolve.BindingContextUtils.getDelegationConstructorCall;
|
||||
@@ -397,35 +398,6 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isGenericToArray(@NotNull FunctionDescriptor function) {
|
||||
if (function.getValueParameters().size() != 1 || function.getTypeParameters().size() != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
KotlinType returnType = function.getReturnType();
|
||||
assert returnType != null : function.toString();
|
||||
KotlinType paramType = function.getValueParameters().get(0).getType();
|
||||
if (KotlinBuiltIns.isArray(returnType) && KotlinBuiltIns.isArray(paramType)) {
|
||||
KotlinType elementType = function.getTypeParameters().get(0).getDefaultType();
|
||||
KotlinBuiltIns builtIns = DescriptorUtilsKt.getBuiltIns(descriptor);
|
||||
if (KotlinTypeChecker.DEFAULT.equalTypes(elementType, builtIns.getArrayElementType(returnType))
|
||||
&& KotlinTypeChecker.DEFAULT.equalTypes(elementType, builtIns.getArrayElementType(paramType))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isNonGenericToArray(@NotNull FunctionDescriptor function) {
|
||||
if (!function.getValueParameters().isEmpty() || !function.getTypeParameters().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
KotlinType returnType = function.getReturnType();
|
||||
return returnType != null && KotlinBuiltIns.isArray(returnType);
|
||||
}
|
||||
|
||||
private void generateToArray() {
|
||||
if (descriptor.getKind() == ClassKind.INTERFACE) return;
|
||||
|
||||
|
||||
@@ -38,15 +38,18 @@ import org.jetbrains.kotlin.psi.KtProperty
|
||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils.isSubclass
|
||||
import org.jetbrains.kotlin.resolve.annotations.hasJvmStaticAnnotation
|
||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfoBefore
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||
import org.jetbrains.kotlin.serialization.deserialization.PLATFORM_DEPENDENT_ANNOTATION_FQ_NAME
|
||||
import org.jetbrains.kotlin.types.ErrorUtils
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||
import org.jetbrains.kotlin.utils.DFS
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
|
||||
import org.jetbrains.org.objectweb.asm.Label
|
||||
@@ -297,3 +300,34 @@ fun KtExpression?.asmType(typeMapper: KotlinTypeMapper, bindingContext: BindingC
|
||||
|
||||
fun KtExpression?.kotlinType(bindingContext: BindingContext) = this?.let(bindingContext::getType)
|
||||
|
||||
fun FunctionDescriptor.isGenericToArray(): Boolean {
|
||||
if (valueParameters.size != 1 || typeParameters.size != 1) return false
|
||||
|
||||
val returnType = returnType ?: throw AssertionError(toString())
|
||||
val paramType = valueParameters[0].type
|
||||
|
||||
if (!KotlinBuiltIns.isArray(returnType) || !KotlinBuiltIns.isArray(paramType)) return false
|
||||
|
||||
val elementType = typeParameters[0].defaultType
|
||||
return KotlinTypeChecker.DEFAULT.equalTypes(elementType, builtIns.getArrayElementType(returnType)) &&
|
||||
KotlinTypeChecker.DEFAULT.equalTypes(elementType, builtIns.getArrayElementType(paramType))
|
||||
}
|
||||
|
||||
fun FunctionDescriptor.isNonGenericToArray(): Boolean {
|
||||
if (!valueParameters.isEmpty() || !typeParameters.isEmpty()) return false
|
||||
|
||||
val returnType = returnType
|
||||
return returnType != null && KotlinBuiltIns.isArray(returnType)
|
||||
}
|
||||
|
||||
fun MemberDescriptor.isToArrayFromCollection(): Boolean {
|
||||
if (this !is FunctionDescriptor) return false
|
||||
|
||||
val containingClassDescriptor = containingDeclaration as? ClassDescriptor ?: return false
|
||||
if (containingClassDescriptor.source == SourceElement.NO_SOURCE) return false
|
||||
|
||||
val collectionClass = builtIns.collection
|
||||
if (!isSubclass(containingClassDescriptor, collectionClass)) return false
|
||||
|
||||
return isGenericToArray() || isNonGenericToArray()
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// WITH_RUNTIME
|
||||
|
||||
// FILE: SingletonCollection.kt
|
||||
package test
|
||||
|
||||
open class SingletonCollection<T>(val value: T) : AbstractCollection<T>() {
|
||||
override val size = 1
|
||||
override fun iterator(): Iterator<T> = listOf(value).iterator()
|
||||
|
||||
protected fun toArray(): Array<Any?> =
|
||||
arrayOf<Any?>(value)
|
||||
|
||||
protected fun <E> toArray(a: Array<E>): Array<E> {
|
||||
a[0] = value as E
|
||||
return a
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: DerivedSingletonCollection.kt
|
||||
package test2
|
||||
|
||||
import test.*
|
||||
|
||||
class DerivedSingletonCollection<T>(value: T) : SingletonCollection<T>(value)
|
||||
|
||||
// FILE: box.kt
|
||||
import test.*
|
||||
import test2.*
|
||||
|
||||
fun box(): String {
|
||||
val sc = SingletonCollection(42)
|
||||
|
||||
val test1 = (sc as java.util.Collection<Int>).toArray()
|
||||
if (test1[0] != 42) return "Failed #1"
|
||||
|
||||
val test2 = arrayOf<Any?>(0)
|
||||
(sc as java.util.Collection<Int>).toArray(test2)
|
||||
if (test2[0] != 42) return "Failed #2"
|
||||
|
||||
val dsc = DerivedSingletonCollection(42)
|
||||
val test3 = (dsc as java.util.Collection<Int>).toArray()
|
||||
if (test3[0] != 42) return "Failed #3"
|
||||
|
||||
val test4 = arrayOf<Any?>(0)
|
||||
(dsc as java.util.Collection<Int>).toArray(test4)
|
||||
if (test4[0] != 42) return "Failed #4"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// WITH_RUNTIME
|
||||
|
||||
// FILE: SingletonCollection.kt
|
||||
package test
|
||||
|
||||
open class SingletonCollection<T>(val value: T) : AbstractCollection<T>() {
|
||||
override val size = 1
|
||||
override fun iterator(): Iterator<T> = listOf(value).iterator()
|
||||
|
||||
protected open fun toArray(): Array<Any?> =
|
||||
arrayOf<Any?>(value)
|
||||
|
||||
protected open fun <E> toArray(a: Array<E>): Array<E> {
|
||||
a[0] = value as E
|
||||
return a
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: JavaSingletonCollection.java
|
||||
import test.*;
|
||||
|
||||
public class JavaSingletonCollection<T> extends SingletonCollection<T> {
|
||||
public JavaSingletonCollection(T value) {
|
||||
super(value);
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: JavaSingletonCollection2.java
|
||||
import test.*;
|
||||
|
||||
public class JavaSingletonCollection2<T> extends SingletonCollection<T> {
|
||||
public JavaSingletonCollection2(T value) {
|
||||
super(value);
|
||||
}
|
||||
|
||||
public Object[] toArray() {
|
||||
return super.toArray();
|
||||
}
|
||||
|
||||
public <E> E[] toArray(E[] arr) {
|
||||
return super.toArray(arr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// FILE: box.kt
|
||||
import test.*
|
||||
|
||||
fun box(): String {
|
||||
val jsc = JavaSingletonCollection(42) as java.util.Collection<Int>
|
||||
val test3 = jsc.toArray()
|
||||
if (test3[0] != 42) return "Failed #3"
|
||||
|
||||
val test4 = arrayOf<Any?>(0)
|
||||
jsc.toArray(test4)
|
||||
if (test4[0] != 42) return "Failed #4"
|
||||
|
||||
val jsc2 = JavaSingletonCollection2(42) as java.util.Collection<Int>
|
||||
val test5 = jsc2.toArray()
|
||||
if (test5[0] != 42) return "Failed #5"
|
||||
|
||||
val test6 = arrayOf<Any?>(0)
|
||||
jsc2.toArray(test6)
|
||||
if (test6[0] != 42) return "Failed #6"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
public final class BoxKt {
|
||||
public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String
|
||||
}
|
||||
|
||||
|
||||
public class test/SingletonCollection {
|
||||
private final field size: int
|
||||
private final field value: java.lang.Object
|
||||
public method <init>(p0: java.lang.Object): void
|
||||
public method getSize(): int
|
||||
public final method getValue(): java.lang.Object
|
||||
public @org.jetbrains.annotations.NotNull method iterator(): java.util.Iterator
|
||||
public final @org.jetbrains.annotations.NotNull method toArray(): java.lang.Object[]
|
||||
public final @org.jetbrains.annotations.NotNull method toArray(@org.jetbrains.annotations.NotNull p0: java.lang.Object[]): java.lang.Object[]
|
||||
}
|
||||
|
||||
|
||||
public final class test2/DerivedSingletonCollection {
|
||||
public method <init>(p0: java.lang.Object): void
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
public final class BoxKt {
|
||||
public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String
|
||||
}
|
||||
|
||||
|
||||
public class test/SingletonCollection {
|
||||
private final field size: int
|
||||
private final field value: java.lang.Object
|
||||
public method <init>(p0: java.lang.Object): void
|
||||
public method getSize(): int
|
||||
public final method getValue(): java.lang.Object
|
||||
public @org.jetbrains.annotations.NotNull method iterator(): java.util.Iterator
|
||||
public @org.jetbrains.annotations.NotNull method toArray(): java.lang.Object[]
|
||||
public @org.jetbrains.annotations.NotNull method toArray(@org.jetbrains.annotations.NotNull p0: java.lang.Object[]): java.lang.Object[]
|
||||
}
|
||||
+12
@@ -16367,6 +16367,18 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("toArrayShouldBePublic.kt")
|
||||
public void testToArrayShouldBePublic() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/toArray/toArrayShouldBePublic.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("toArrayShouldBePublicWithJava.kt")
|
||||
public void testToArrayShouldBePublicWithJava() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/toArray/toArrayShouldBePublicWithJava.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("toTypedArray.kt")
|
||||
public void testToTypedArray() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/toArray/toTypedArray.kt");
|
||||
|
||||
@@ -16367,6 +16367,18 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("toArrayShouldBePublic.kt")
|
||||
public void testToArrayShouldBePublic() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/toArray/toArrayShouldBePublic.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("toArrayShouldBePublicWithJava.kt")
|
||||
public void testToArrayShouldBePublicWithJava() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/toArray/toArrayShouldBePublicWithJava.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("toTypedArray.kt")
|
||||
public void testToTypedArray() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/toArray/toTypedArray.kt");
|
||||
|
||||
+12
@@ -16367,6 +16367,18 @@ public class LightAnalysisModeCodegenTestGenerated extends AbstractLightAnalysis
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("toArrayShouldBePublic.kt")
|
||||
public void testToArrayShouldBePublic() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/toArray/toArrayShouldBePublic.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("toArrayShouldBePublicWithJava.kt")
|
||||
public void testToArrayShouldBePublicWithJava() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/toArray/toArrayShouldBePublicWithJava.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("toTypedArray.kt")
|
||||
public void testToTypedArray() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/toArray/toTypedArray.kt");
|
||||
|
||||
Reference in New Issue
Block a user