From fd0c92e307c4adb0b43f4e159e05d30d4b41f7cd Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Fri, 25 Sep 2015 13:59:51 +0300 Subject: [PATCH] Record inner class info for interface and `DefaultImpls` --- .../codegen/InterfaceImplBodyCodegen.kt | 22 +++++++++++++++---- .../nullabilityAnnotations/Generic.java | 6 ++++- .../nullabilityAnnotations/Primitives.java | 6 ++++- .../PrivateInTrait.java | 12 +++++++++- .../nullabilityAnnotations/Trait.java | 6 ++++- .../TraitClassObjectField.java | 4 ++++ .../boxWithJava/interfaceDefaultImpls/B.java | 5 +++++ .../boxWithJava/interfaceDefaultImpls/main.kt | 10 +++++++++ .../bytecodeText/interfaceDefaultImpl.kt | 11 ++++++++++ .../method/TraitImpl.java | 4 ++-- .../codegen/BytecodeTextTestGenerated.java | 6 +++++ .../kotlin/codegen/InnerClassInfoGenTest.java | 19 +++++++++++++--- .../BlackBoxWithJavaCodegenTestGenerated.java | 6 +++++ 13 files changed, 104 insertions(+), 13 deletions(-) create mode 100644 compiler/testData/codegen/boxWithJava/interfaceDefaultImpls/B.java create mode 100644 compiler/testData/codegen/boxWithJava/interfaceDefaultImpls/main.kt create mode 100644 compiler/testData/codegen/bytecodeText/interfaceDefaultImpl.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/InterfaceImplBodyCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/InterfaceImplBodyCodegen.kt index 998f4698854..57e5dfd50d0 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/InterfaceImplBodyCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/InterfaceImplBodyCodegen.kt @@ -23,17 +23,21 @@ import org.jetbrains.kotlin.codegen.AsmUtil.writeKotlinSyntheticClassAnnotation import org.jetbrains.kotlin.codegen.context.ClassContext import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorImpl +import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.load.java.JvmAnnotationNames.KotlinSyntheticClass.Kind.LOCAL_TRAIT_IMPL import org.jetbrains.kotlin.load.java.JvmAnnotationNames.KotlinSyntheticClass.Kind.TRAIT_IMPL import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor +import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.JetClassOrObject import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.jvm.diagnostics.DelegationToTraitImpl import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature -import org.jetbrains.org.objectweb.asm.Opcodes.ACC_FINAL -import org.jetbrains.org.objectweb.asm.Opcodes.ACC_PUBLIC +import org.jetbrains.kotlin.resolve.scopes.JetScope +import org.jetbrains.org.objectweb.asm.Opcodes.* import org.jetbrains.org.objectweb.asm.Opcodes.V1_6 +import java.util.* public class InterfaceImplBodyCodegen( aClass: JetClassOrObject, @@ -45,13 +49,23 @@ public class InterfaceImplBodyCodegen( override fun generateDeclaration() { v.defineClass( - myClass, V1_6, ACC_PUBLIC or ACC_FINAL, - typeMapper.mapDefaultImpls(descriptor).getInternalName(), + myClass, V1_6, ACC_PUBLIC or ACC_FINAL or ACC_STATIC, + typeMapper.mapDefaultImpls(descriptor).internalName, null, "java/lang/Object", ArrayUtil.EMPTY_STRING_ARRAY ) v.visitSource(myClass.getContainingFile().getName(), null) } + override fun classForInnerClassRecord(): ClassDescriptor? { + if (DescriptorUtils.isLocal(descriptor)) return null + val classDescriptorImpl = ClassDescriptorImpl( + descriptor, Name.identifier(JvmAbi.DEFAULT_IMPLS_CLASS_NAME), + Modality.FINAL, Collections.emptyList(), SourceElement.NO_SOURCE) + + classDescriptorImpl.initialize(JetScope.Empty, emptySet(), null) + return classDescriptorImpl + } + override fun generateSyntheticParts() { for (memberDescriptor in descriptor.getDefaultType().getMemberScope().getAllDescriptors()) { if (memberDescriptor !is CallableMemberDescriptor) continue diff --git a/compiler/testData/asJava/lightClasses/nullabilityAnnotations/Generic.java b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/Generic.java index df6cd40befb..aa3337f3398 100644 --- a/compiler/testData/asJava/lightClasses/nullabilityAnnotations/Generic.java +++ b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/Generic.java @@ -9,4 +9,8 @@ public interface Generic { @org.jetbrains.annotations.Nullable NN b1(@org.jetbrains.annotations.Nullable NN nn); -} + + @kotlin.jvm.internal.KotlinSyntheticClass(version = {0, 27, 0}, abiVersion = 27, kind = kotlin.jvm.internal.KotlinSyntheticClass.Kind.TRAIT_IMPL) + static final class DefaultImpls { + } +} \ No newline at end of file diff --git a/compiler/testData/asJava/lightClasses/nullabilityAnnotations/Primitives.java b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/Primitives.java index 68f2315c3f9..de71d90c24a 100644 --- a/compiler/testData/asJava/lightClasses/nullabilityAnnotations/Primitives.java +++ b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/Primitives.java @@ -40,4 +40,8 @@ public interface Primitives { float getFloat(); double getDouble(); -} + + @kotlin.jvm.internal.KotlinSyntheticClass(version = {0, 27, 0}, abiVersion = 27, kind = kotlin.jvm.internal.KotlinSyntheticClass.Kind.TRAIT_IMPL) + static final class DefaultImpls { + } +} \ No newline at end of file diff --git a/compiler/testData/asJava/lightClasses/nullabilityAnnotations/PrivateInTrait.java b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/PrivateInTrait.java index d64ea0c1fd6..727d6356453 100644 --- a/compiler/testData/asJava/lightClasses/nullabilityAnnotations/PrivateInTrait.java +++ b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/PrivateInTrait.java @@ -1,2 +1,12 @@ public interface PrivateInTrait { -} + @kotlin.jvm.internal.KotlinSyntheticClass(version = {0, 27, 0}, abiVersion = 27, kind = kotlin.jvm.internal.KotlinSyntheticClass.Kind.TRAIT_IMPL) + static final class DefaultImpls { + @org.jetbrains.annotations.NotNull + static java.lang.String getNn(PrivateInTrait $this) { /* compiled code */ } + + static void setNn(@org.jetbrains.annotations.NotNull PrivateInTrait $this, java.lang.String value) { /* compiled code */ } + + @org.jetbrains.annotations.Nullable + static java.lang.String getN(PrivateInTrait $this) { /* compiled code */ } + } +} \ No newline at end of file diff --git a/compiler/testData/asJava/lightClasses/nullabilityAnnotations/Trait.java b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/Trait.java index 00cb9edff1f..decb4ff3cbd 100644 --- a/compiler/testData/asJava/lightClasses/nullabilityAnnotations/Trait.java +++ b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/Trait.java @@ -34,4 +34,8 @@ public interface Trait { java.lang.String getNotNullVar(); void setNotNullVar(@org.jetbrains.annotations.NotNull java.lang.String p); -} + + @kotlin.jvm.internal.KotlinSyntheticClass(version = {0, 27, 0}, abiVersion = 27, kind = kotlin.jvm.internal.KotlinSyntheticClass.Kind.TRAIT_IMPL) + static final class DefaultImpls { + } +} \ No newline at end of file diff --git a/compiler/testData/asJava/lightClasses/nullabilityAnnotations/TraitClassObjectField.java b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/TraitClassObjectField.java index 6a1577a11e3..6501c03d518 100644 --- a/compiler/testData/asJava/lightClasses/nullabilityAnnotations/TraitClassObjectField.java +++ b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/TraitClassObjectField.java @@ -15,4 +15,8 @@ public interface TraitClassObjectField { private Companion() { /* compiled code */ } } + + @kotlin.jvm.internal.KotlinSyntheticClass(version = {0, 27, 0}, abiVersion = 27, kind = kotlin.jvm.internal.KotlinSyntheticClass.Kind.TRAIT_IMPL) + static final class DefaultImpls { + } } \ No newline at end of file diff --git a/compiler/testData/codegen/boxWithJava/interfaceDefaultImpls/B.java b/compiler/testData/codegen/boxWithJava/interfaceDefaultImpls/B.java new file mode 100644 index 00000000000..423e5a8a207 --- /dev/null +++ b/compiler/testData/codegen/boxWithJava/interfaceDefaultImpls/B.java @@ -0,0 +1,5 @@ +class B { + static String test(A x) { + return A.DefaultImpls.foo(x); + } +} diff --git a/compiler/testData/codegen/boxWithJava/interfaceDefaultImpls/main.kt b/compiler/testData/codegen/boxWithJava/interfaceDefaultImpls/main.kt new file mode 100644 index 00000000000..1114dd547a4 --- /dev/null +++ b/compiler/testData/codegen/boxWithJava/interfaceDefaultImpls/main.kt @@ -0,0 +1,10 @@ +interface A { + fun foo() = "OK" +} + +fun box(): String { + val result = B.test(object : A {}) + if (result != "OK") return "fail: $result" + + return "OK" +} diff --git a/compiler/testData/codegen/bytecodeText/interfaceDefaultImpl.kt b/compiler/testData/codegen/bytecodeText/interfaceDefaultImpl.kt new file mode 100644 index 00000000000..b899192f6e1 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/interfaceDefaultImpl.kt @@ -0,0 +1,11 @@ +interface A { + fun foo() = 1 + + object C { + + } + + companion object {} +} + +// 2 public final static INNERCLASS A\$DefaultImpls A DefaultImpls diff --git a/compiler/testData/compileJavaAgainstKotlin/method/TraitImpl.java b/compiler/testData/compileJavaAgainstKotlin/method/TraitImpl.java index 50d468d5fe5..4ac8de0fbdb 100644 --- a/compiler/testData/compileJavaAgainstKotlin/method/TraitImpl.java +++ b/compiler/testData/compileJavaAgainstKotlin/method/TraitImpl.java @@ -4,8 +4,8 @@ import java.util.ArrayList; abstract class TraitImpl implements Trait { { - Trait$DefaultImpls.simple(this); + Trait.DefaultImpls.simple(this); - Trait$DefaultImpls.generic(this, new ArrayList()); + Trait.DefaultImpls.generic(this, new ArrayList()); } } diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java index 85d08aef26e..f2f19127ed1 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java @@ -143,6 +143,12 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { doTest(fileName); } + @TestMetadata("interfaceDefaultImpl.kt") + public void testInterfaceDefaultImpl() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/interfaceDefaultImpl.kt"); + doTest(fileName); + } + @TestMetadata("javaExtensionPropertyIntrinsic.kt") public void testJavaExtensionPropertyIntrinsic() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/javaExtensionPropertyIntrinsic.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/InnerClassInfoGenTest.java b/compiler/tests/org/jetbrains/kotlin/codegen/InnerClassInfoGenTest.java index f63667e92ea..58fffa48423 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/InnerClassInfoGenTest.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/InnerClassInfoGenTest.java @@ -16,6 +16,8 @@ package org.jetbrains.kotlin.codegen; +import kotlin.CollectionsKt; +import kotlin.jvm.functions.Function1; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.backend.common.output.OutputFile; @@ -86,6 +88,7 @@ public class InnerClassInfoGenTest extends CodegenTestCase { checkAccess("A", "Annotation", ACC_PUBLIC | ACC_STATIC | ACC_INTERFACE | ACC_ABSTRACT | ACC_ANNOTATION); checkAccess("A", "Enum", ACC_PUBLIC | ACC_STATIC | ACC_FINAL | ACC_ENUM); checkAccess("A", "Trait", ACC_PUBLIC | ACC_STATIC | ACC_INTERFACE | ACC_ABSTRACT); + checkAccess("A$Trait", "DefaultImpls", ACC_PUBLIC | ACC_STATIC | ACC_FINAL); checkAccess("A", "OpenStaticClass", ACC_PUBLIC | ACC_STATIC); checkAccess("A", "FinalStaticClass", ACC_PUBLIC | ACC_STATIC | ACC_FINAL); @@ -102,10 +105,20 @@ public class InnerClassInfoGenTest extends CodegenTestCase { - private void checkAccess(@NotNull String outerName, @NotNull String innerName, int accessFlags) { + private void checkAccess(@NotNull String outerName, @NotNull final String innerName, int accessFlags) { String name = outerName + "$" + innerName; - InnerClassAttribute attribute = new InnerClassAttribute(name, outerName, innerName, accessFlags); - extractAndCompareInnerClasses(name, attribute); + InnerClassAttribute attribute = CollectionsKt.single(extractInnerClasses(name), + new Function1() { + @Override + public Boolean invoke(InnerClassAttribute attribute) { + return innerName.equals(attribute.innerName); + } + } + ); + + InnerClassAttribute expectedAttribute = new InnerClassAttribute(name, outerName, innerName, accessFlags); + + assertEquals(expectedAttribute, attribute); } private void extractAndCompareInnerClasses(@NotNull String className, @NotNull InnerClassAttribute... expectedInnerClasses) { diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java index d83ff7309bc..35c63755834 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java @@ -59,6 +59,12 @@ public class BlackBoxWithJavaCodegenTestGenerated extends AbstractBlackBoxCodege doTestWithJava(fileName); } + @TestMetadata("interfaceDefaultImpls") + public void testInterfaceDefaultImpls() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/interfaceDefaultImpls/"); + doTestWithJava(fileName); + } + @TestMetadata("platformName") public void testPlatformName() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/platformName/");