Support mixed compilation of new default with non-default or @JvmDefault
This commit is contained in:
committed by
Mikhail Bogdanov
parent
a3f930d2e4
commit
e45a892499
@@ -222,8 +222,11 @@ public abstract class ClassBodyCodegen extends MemberCodegen<KtPureClassOrObject
|
||||
for (Map.Entry<FunctionDescriptor, FunctionDescriptor> entry : CodegenUtil.getNonPrivateTraitMethods(descriptor).entrySet()) {
|
||||
FunctionDescriptor interfaceFun = entry.getKey();
|
||||
//skip java 8 default methods
|
||||
if (!CodegenUtilKt.isDefinitelyNotDefaultImplsMethod(interfaceFun) && !JvmAnnotationUtilKt
|
||||
.isCompiledToJvmDefaultIfNoAbstract(interfaceFun, state.getJvmDefaultMode())) {
|
||||
if (!CodegenUtilKt.isDefinitelyNotDefaultImplsMethod(interfaceFun) &&
|
||||
!JvmAnnotationUtilKt.isCallableMemberCompiledToJvmDefaultIfNoAbstract(
|
||||
DescriptorUtils.unwrapFakeOverrideToAnyDeclaration(interfaceFun), state.getJvmDefaultMode()
|
||||
)
|
||||
) {
|
||||
generateDelegationToDefaultImpl(interfaceFun, entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -732,7 +732,9 @@ public class FunctionCodegen {
|
||||
@NotNull JvmDefaultMode jvmDefaultMode
|
||||
) {
|
||||
return OwnerKind.DEFAULT_IMPLS == context.getContextKind() &&
|
||||
JvmAnnotationUtilKt.isCompiledToJvmDefaultIfNoAbstract(functionDescriptor, jvmDefaultMode) &&
|
||||
JvmAnnotationUtilKt
|
||||
.isCompiledToJvmDefaultIfNoAbstract(DescriptorUtils.unwrapFakeOverrideToAnyDeclaration(functionDescriptor),
|
||||
jvmDefaultMode) &&
|
||||
jvmDefaultMode.isCompatibility();
|
||||
}
|
||||
|
||||
|
||||
@@ -1540,7 +1540,7 @@ class KotlinTypeMapper @JvmOverloads constructor(
|
||||
return if (descriptor is AccessorForConstructorDescriptor) false else isAccessor(descriptor)
|
||||
}
|
||||
|
||||
private fun findAnyDeclaration(function: FunctionDescriptor): FunctionDescriptor {
|
||||
internal fun findAnyDeclaration(function: FunctionDescriptor): FunctionDescriptor {
|
||||
return if (function.kind == CallableMemberDescriptor.Kind.DECLARATION) {
|
||||
function
|
||||
} else findBaseDeclaration(function)
|
||||
|
||||
+13
-2
@@ -8,13 +8,17 @@ package org.jetbrains.kotlin.resolve.jvm.annotations
|
||||
import org.jetbrains.kotlin.config.JvmDefaultMode
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotated
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.deserialization.PLATFORM_DEPENDENT_ANNOTATION_FQ_NAME
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi.JVM_FIELD_ANNOTATION_FQ_NAME
|
||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils.isInterface
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor
|
||||
|
||||
val JVM_DEFAULT_FQ_NAME = FqName("kotlin.jvm.JvmDefault")
|
||||
val JVM_OVERLOADS_FQ_NAME = FqName("kotlin.jvm.JvmOverloads")
|
||||
@@ -44,8 +48,15 @@ fun DeclarationDescriptor.hasJvmFieldAnnotation(): Boolean =
|
||||
fun DeclarationDescriptor.isCallableMemberCompiledToJvmDefaultIfNoAbstract(jvmDefault: JvmDefaultMode): Boolean =
|
||||
this is CallableMemberDescriptor && isCompiledToJvmDefaultIfNoAbstract(jvmDefault)
|
||||
|
||||
fun CallableMemberDescriptor.isCompiledToJvmDefaultIfNoAbstract(jvmDefault: JvmDefaultMode): Boolean =
|
||||
jvmDefault.forAllMehtodsWithBody || DescriptorUtils.getDirectMember(this).annotations.hasAnnotation(JVM_DEFAULT_FQ_NAME)
|
||||
fun CallableMemberDescriptor.isCompiledToJvmDefaultIfNoAbstract(jvmDefault: JvmDefaultMode): Boolean {
|
||||
val directMember = DescriptorUtils.getDirectMember(this)
|
||||
|
||||
val clazz = directMember.containingDeclaration
|
||||
|
||||
if (directMember.annotations.hasAnnotation(JVM_DEFAULT_FQ_NAME)) return true
|
||||
if (clazz !is DeserializedClassDescriptor) return jvmDefault.forAllMethodsWithBody
|
||||
return JvmProtoBufUtil.isNewPlaceForBodyGeneration(clazz.classProto)
|
||||
}
|
||||
|
||||
fun CallableMemberDescriptor.hasJvmDefaultAnnotation(): Boolean =
|
||||
DescriptorUtils.getDirectMember(this).annotations.hasAnnotation(JVM_DEFAULT_FQ_NAME)
|
||||
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
// FULL_JDK
|
||||
// FILE: 1.kt
|
||||
interface KInterface {
|
||||
fun call(): List<String> {
|
||||
return Thread.currentThread().getStackTrace().map { it.className + "." + it.methodName }
|
||||
}
|
||||
|
||||
fun superCall() = Thread.currentThread().getStackTrace().map { it.className + "." + it.methodName }
|
||||
}
|
||||
|
||||
// FILE: main.kt
|
||||
// !JVM_DEFAULT_MODE: all-compatibility
|
||||
// JVM_TARGET: 1.8
|
||||
interface KInterface2 : KInterface {
|
||||
override fun superCall() = super.superCall()
|
||||
}
|
||||
|
||||
class Foo: KInterface2 {
|
||||
fun superCall2() = super<KInterface2>.superCall()
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
var result = Foo().call()
|
||||
if (result[1] != "KInterface\$DefaultImpls.call") return "fail 1: ${result[1]}"
|
||||
if (result[2] != "KInterface2\$DefaultImpls.call") return "fail 2: ${result[2]}"
|
||||
if (result[3] != "Foo.call") return "fail 3: ${result[3]}"
|
||||
if (result[4] != "MainKt.box") return "fail 4: ${result[4]}"
|
||||
|
||||
result = Foo().superCall2()
|
||||
if (result[1] != "KInterface\$DefaultImpls.superCall") return "fail 1: ${result[1]}"
|
||||
if (result[2] != "KInterface2.superCall") return "fail 2: ${result[2]}"
|
||||
if (result[3] != "Foo.superCall2") return "fail 3: ${result[3]}"
|
||||
if (result[4] != "MainKt.box") return "fail 4: ${result[4]}"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
Vendored
+38
@@ -0,0 +1,38 @@
|
||||
// FULL_JDK
|
||||
// WITH_RUNTIME
|
||||
// JVM_TARGET: 1.8
|
||||
// FILE: 1.kt
|
||||
// !JVM_DEFAULT_MODE: enable
|
||||
interface KInterface {
|
||||
@JvmDefault
|
||||
fun call(): List<String> {
|
||||
return Thread.currentThread().getStackTrace().map { it.className + "." + it.methodName }
|
||||
}
|
||||
|
||||
fun superCall() = Thread.currentThread().getStackTrace().map { it.className + "." + it.methodName }
|
||||
}
|
||||
|
||||
// FILE: main.kt
|
||||
// !JVM_DEFAULT_MODE: all
|
||||
interface KInterface2 : KInterface {
|
||||
override fun superCall() = super.superCall()
|
||||
}
|
||||
|
||||
class Foo: KInterface2 {
|
||||
fun superCall2() = super<KInterface2>.superCall()
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
var result = Foo().call()
|
||||
if (result[1] != "KInterface.call") return "fail 1: ${result[1]}"
|
||||
if (result[2] != "MainKt.box") return "fail 2: ${result[2]}"
|
||||
|
||||
result = Foo().superCall2()
|
||||
if (result[1] != "KInterface\$DefaultImpls.superCall") return "fail 1: ${result[1]}"
|
||||
if (result[2] != "KInterface2.superCall") return "fail 2: ${result[2]}"
|
||||
if (result[3] != "Foo.superCall2") return "fail 3: ${result[3]}"
|
||||
if (result[4] != "MainKt.box") return "fail 4: ${result[4]}"
|
||||
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+23
@@ -459,6 +459,29 @@ public class CompileKotlinAgainstKotlinTestGenerated extends AbstractCompileKotl
|
||||
runTest("compiler/testData/compileKotlinAgainstKotlin/jvm8/defaults/allCompatibility/superPropAccessFromInterface2.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/compileKotlinAgainstKotlin/jvm8/defaults/interop")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class Interop extends AbstractCompileKotlinAgainstKotlinTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInInterop() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/compileKotlinAgainstKotlin/jvm8/defaults/interop"), Pattern.compile("^(.+)\\.kt$"), null, true);
|
||||
}
|
||||
|
||||
@TestMetadata("newAndOldSchemes.kt")
|
||||
public void testNewAndOldSchemes() throws Exception {
|
||||
runTest("compiler/testData/compileKotlinAgainstKotlin/jvm8/defaults/interop/newAndOldSchemes.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("newSchemeWithJvmDefault.kt")
|
||||
public void testNewSchemeWithJvmDefault() throws Exception {
|
||||
runTest("compiler/testData/compileKotlinAgainstKotlin/jvm8/defaults/interop/newSchemeWithJvmDefault.kt");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/compileKotlinAgainstKotlin/jvm8/jvm8against6")
|
||||
|
||||
Generated
+23
@@ -454,6 +454,29 @@ public class IrCompileKotlinAgainstKotlinTestGenerated extends AbstractIrCompile
|
||||
runTest("compiler/testData/compileKotlinAgainstKotlin/jvm8/defaults/allCompatibility/superPropAccessFromInterface2.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/compileKotlinAgainstKotlin/jvm8/defaults/interop")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class Interop extends AbstractIrCompileKotlinAgainstKotlinTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM_IR, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInInterop() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/compileKotlinAgainstKotlin/jvm8/defaults/interop"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
|
||||
}
|
||||
|
||||
@TestMetadata("newAndOldSchemes.kt")
|
||||
public void testNewAndOldSchemes() throws Exception {
|
||||
runTest("compiler/testData/compileKotlinAgainstKotlin/jvm8/defaults/interop/newAndOldSchemes.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("newSchemeWithJvmDefault.kt")
|
||||
public void testNewSchemeWithJvmDefault() throws Exception {
|
||||
runTest("compiler/testData/compileKotlinAgainstKotlin/jvm8/defaults/interop/newSchemeWithJvmDefault.kt");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/compileKotlinAgainstKotlin/jvm8/jvm8against6")
|
||||
|
||||
Reference in New Issue
Block a user