Don't generate delegates on overriding jvm8 interfaces

This commit is contained in:
Mikhael Bogdanov
2016-05-19 14:19:02 +03:00
parent 01aa89b1ea
commit 331341bd4d
7 changed files with 154 additions and 3 deletions
@@ -1326,7 +1326,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
for (Map.Entry<FunctionDescriptor, FunctionDescriptor> entry : CodegenUtil.getNonPrivateTraitMethods(descriptor).entrySet()) {
FunctionDescriptor traitFun = entry.getKey();
//skip java 8 default methods
if (!(traitFun instanceof JavaCallableMemberDescriptor)) {
if (!(traitFun instanceof JavaCallableMemberDescriptor || isJvm8InterfaceMember(traitFun, state))) {
generateDelegationToTraitImpl(traitFun, entry.getValue());
}
}
@@ -28,11 +28,11 @@ import org.jetbrains.kotlin.codegen.context.CodegenContext;
import org.jetbrains.kotlin.codegen.context.FacadePartWithSourceFile;
import org.jetbrains.kotlin.codegen.context.MethodContext;
import org.jetbrains.kotlin.codegen.context.RootContext;
import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.load.java.descriptors.JavaPropertyDescriptor;
import org.jetbrains.kotlin.load.kotlin.ModuleMapping;
import org.jetbrains.kotlin.load.kotlin.ModuleVisibilityUtilsKt;
import org.jetbrains.kotlin.load.kotlin.*;
import org.jetbrains.kotlin.psi.Call;
import org.jetbrains.kotlin.psi.KtFile;
import org.jetbrains.kotlin.psi.KtFunction;
@@ -43,7 +43,9 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.inline.InlineUtil;
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor;
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor;
import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.org.objectweb.asm.Opcodes;
import java.io.File;
@@ -58,6 +60,32 @@ public class JvmCodegenUtil {
private JvmCodegenUtil() {
}
public static boolean isJvm6Interface(@NotNull DeclarationDescriptor descriptor, @NotNull GenerationState state) {
if (!DescriptorUtils.isInterface(descriptor)) {
return false;
}
if (descriptor instanceof DeserializedClassDescriptor) {
SourceElement source = ((DeserializedClassDescriptor) descriptor).getSource();
if (source instanceof KotlinJvmBinarySourceElement) {
KotlinJvmBinaryClass binaryClass = ((KotlinJvmBinarySourceElement) source).getBinaryClass();
assert binaryClass instanceof FileBasedKotlinClass :
"KotlinJvmBinaryClass should be subclass of FileBasedKotlinClass, but " + binaryClass;
return ((FileBasedKotlinClass) binaryClass).getClassVersion() == Opcodes.V1_6;
}
}
return !state.isJvm8Target();
}
public static boolean isJvm8Interface(@NotNull DeclarationDescriptor descriptor, @NotNull GenerationState state) {
return DescriptorUtils.isInterface(descriptor) && !isJvm6Interface(descriptor, state);
}
public static boolean isJvm8InterfaceMember(@NotNull CallableMemberDescriptor descriptor, @NotNull GenerationState state) {
DeclarationDescriptor declaration = descriptor.getContainingDeclaration();
return DescriptorUtils.isInterface(declaration) && !isJvm6Interface(declaration, state);
}
public static boolean isJvmInterface(DeclarationDescriptor descriptor) {
if (descriptor instanceof ClassDescriptor) {
ClassKind kind = ((ClassDescriptor) descriptor).getKind();
@@ -0,0 +1,21 @@
// KOTLIN_CONFIGURATION_FLAGS: +JVM.JVM_8_TARGET
// WITH_RUNTIME
// FULL_JDK
interface Test {
fun test() {
}
}
class TestClass : Test {
}
fun box(): String {
try {
TestClass::class.java.getDeclaredMethod("test")
}
catch (e: NoSuchMethodException) {
return "OK"
}
return "fail"
}
@@ -0,0 +1,21 @@
// KOTLIN_CONFIGURATION_FLAGS: +JVM.JVM_8_TARGET
// WITH_RUNTIME
// FULL_JDK
interface Test {
fun test() {
}
}
interface Test2 : Test {
}
fun box(): String {
try {
Test2::class.java.getDeclaredMethod("test")
}
catch (e: NoSuchMethodException) {
return "OK"
}
return "fail"
}
@@ -0,0 +1,25 @@
// KOTLIN_CONFIGURATION_FLAGS: +JVM.JVM_8_TARGET
// WITH_RUNTIME
// FULL_JDK
interface Test {
fun test() {
}
}
interface Test2 : Test {
}
interface Test3 : Test2 {
}
fun box(): String {
try {
Test3::class.java.getDeclaredMethod("test")
}
catch (e: NoSuchMethodException) {
return "OK"
}
return "fail"
}
+14
View File
@@ -0,0 +1,14 @@
// KOTLIN_CONFIGURATION_FLAGS: +JVM.JVM_8_TARGET
interface Test {
fun test(): String {
return "OK"
}
}
class TestClass : Test {
}
fun box(): String {
return TestClass().test()
}
@@ -119,6 +119,48 @@ public class BlackBoxWithJava8CodegenTestGenerated extends AbstractBlackBoxCodeg
doTest(fileName);
}
@TestMetadata("compiler/testData/codegen/java8/box/jvm8")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Jvm8 extends AbstractBlackBoxCodegenTest {
public void testAllFilesPresentInJvm8() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/java8/box/jvm8"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("simpleCall.kt")
public void testSimpleCall() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/java8/box/jvm8/simpleCall.kt");
doTest(fileName);
}
@TestMetadata("compiler/testData/codegen/java8/box/jvm8/noDelegation")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class NoDelegation extends AbstractBlackBoxCodegenTest {
public void testAllFilesPresentInNoDelegation() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/java8/box/jvm8/noDelegation"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("noDelegationToDefaultMethodInClass.kt")
public void testNoDelegationToDefaultMethodInClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/java8/box/jvm8/noDelegation/noDelegationToDefaultMethodInClass.kt");
doTest(fileName);
}
@TestMetadata("noDelegationToDefaultMethodInInterface.kt")
public void testNoDelegationToDefaultMethodInInterface() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/java8/box/jvm8/noDelegation/noDelegationToDefaultMethodInInterface.kt");
doTest(fileName);
}
@TestMetadata("noDelegationToDefaultMethodInInterface2.kt")
public void testNoDelegationToDefaultMethodInInterface2() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/java8/box/jvm8/noDelegation/noDelegationToDefaultMethodInInterface2.kt");
doTest(fileName);
}
}
}
@TestMetadata("compiler/testData/codegen/java8/box/mapRemove")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)