diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/DelegatedMemberGenerator.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/DelegatedMemberGenerator.kt index b2a3edac8c2..b618818ea94 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/DelegatedMemberGenerator.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/DelegatedMemberGenerator.kt @@ -5,9 +5,11 @@ package org.jetbrains.kotlin.fir.backend.generators +import org.jetbrains.kotlin.descriptors.Modality +import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.backend.* import org.jetbrains.kotlin.fir.declarations.* -import org.jetbrains.kotlin.fir.isJavaDefault +import org.jetbrains.kotlin.fir.declarations.utils.modality import org.jetbrains.kotlin.fir.scopes.impl.delegatedWrapperData import org.jetbrains.kotlin.fir.scopes.processAllFunctions import org.jetbrains.kotlin.fir.scopes.processAllProperties @@ -25,6 +27,9 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrReturnImpl import org.jetbrains.kotlin.ir.types.classifierOrNull import org.jetbrains.kotlin.ir.types.isNothing import org.jetbrains.kotlin.ir.types.isUnit +import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.JvmNames.JVM_DEFAULT_CLASS_ID /** * A generator for delegated members from implementation by delegation. @@ -37,6 +42,10 @@ class DelegatedMemberGenerator( private val components: Fir2IrComponents ) : Fir2IrComponents by components { + companion object { + private val PLATFORM_DEPENDENT_CLASS_ID = ClassId.topLevel(FqName("kotlin.internal.PlatformDependent")) + } + private val baseFunctionSymbols = mutableMapOf>() private val basePropertySymbols = mutableMapOf>() @@ -55,7 +64,7 @@ class DelegatedMemberGenerator( declarationStorage.getIrFunctionSymbol(unwrapped.symbol).owner as? IrSimpleFunction ?: return@processAllFunctions - if (unwrapped.isJavaDefault) { + if (shouldSkipDelegationFor(unwrapped)) { return@processAllFunctions } @@ -78,6 +87,10 @@ class DelegatedMemberGenerator( val member = declarationStorage.getIrPropertySymbol(unwrapped.symbol).owner as? IrProperty ?: return@processAllProperties + if (shouldSkipDelegationFor(unwrapped)) { + return@processAllProperties + } + val irSubProperty = generateDelegatedProperty( subClass, firSubClass, irField, member, propertySymbol.fir ) @@ -87,6 +100,26 @@ class DelegatedMemberGenerator( } } + private fun shouldSkipDelegationFor(unwrapped: FirCallableDeclaration): Boolean { + // See org.jetbrains.kotlin.resolve.jvm.JvmDelegationFilter + return (unwrapped is FirSimpleFunction && unwrapped.isDefaultJavaMethod()) || + unwrapped.hasAnnotation(JVM_DEFAULT_CLASS_ID) || + unwrapped.hasAnnotation(PLATFORM_DEPENDENT_CLASS_ID) + } + + private fun FirSimpleFunction.isDefaultJavaMethod(): Boolean = + when { + isIntersectionOverride -> + baseForIntersectionOverride!!.isDefaultJavaMethod() + isSubstitutionOverride -> + originalForSubstitutionOverride!!.isDefaultJavaMethod() + else -> { + // Check that we have a non-abstract method from Java interface + origin == FirDeclarationOrigin.Enhancement && modality == Modality.OPEN + } + } + + fun bindDelegatedMembersOverriddenSymbols(irClass: IrClass) { val superClasses by lazy(LazyThreadSafetyMode.NONE) { irClass.superTypes.mapNotNullTo(mutableSetOf()) { it.classifierOrNull?.owner as? IrClass } diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java index 05fc49391c2..383a9155f4a 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java @@ -25090,6 +25090,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/jvm8/defaults/delegationBy"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); } + @Test + @TestMetadata("javaDefaultMethod.kt") + public void testJavaDefaultMethod() throws Exception { + runTest("compiler/testData/codegen/box/jvm8/defaults/delegationBy/javaDefaultMethod.kt"); + } + @Test @TestMetadata("simple.kt") public void testSimple() throws Exception { diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/ClassMembers.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/ClassMembers.kt index 33c54d4d6bc..82ed2b4791f 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/ClassMembers.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/ClassMembers.kt @@ -59,12 +59,6 @@ inline val D.baseForIntersectionOverride: D inline val > S.baseForIntersectionOverride: S? get() = fir.baseForIntersectionOverride?.symbol as S? -val FirSimpleFunction.isJavaDefault: Boolean - get() { - if (isIntersectionOverride) return baseForIntersectionOverride!!.isJavaDefault - return origin == FirDeclarationOrigin.Enhancement && modality == Modality.OPEN - } - inline fun D.originalIfFakeOverride(): D? = originalForSubstitutionOverride ?: baseForIntersectionOverride diff --git a/compiler/testData/codegen/box/compileKotlinAgainstKotlin/jvm8/defaults/allCompatibility/delegationBy/simple.kt b/compiler/testData/codegen/box/compileKotlinAgainstKotlin/jvm8/defaults/allCompatibility/delegationBy/simple.kt index c3d244d02d1..501b144628a 100644 --- a/compiler/testData/codegen/box/compileKotlinAgainstKotlin/jvm8/defaults/allCompatibility/delegationBy/simple.kt +++ b/compiler/testData/codegen/box/compileKotlinAgainstKotlin/jvm8/defaults/allCompatibility/delegationBy/simple.kt @@ -1,6 +1,4 @@ // !JVM_DEFAULT_MODE: all-compatibility -// IGNORE_BACKEND_FIR: JVM_IR -// FIR status: FailK // TARGET_BACKEND: JVM // JVM_TARGET: 1.8 // WITH_STDLIB diff --git a/compiler/testData/codegen/box/compileKotlinAgainstKotlin/jvm8/defaults/allCompatibility/delegationBy/simpleProperty.kt b/compiler/testData/codegen/box/compileKotlinAgainstKotlin/jvm8/defaults/allCompatibility/delegationBy/simpleProperty.kt index e097efaf086..870f4a93583 100644 --- a/compiler/testData/codegen/box/compileKotlinAgainstKotlin/jvm8/defaults/allCompatibility/delegationBy/simpleProperty.kt +++ b/compiler/testData/codegen/box/compileKotlinAgainstKotlin/jvm8/defaults/allCompatibility/delegationBy/simpleProperty.kt @@ -1,6 +1,4 @@ // !JVM_DEFAULT_MODE: all-compatibility -// IGNORE_BACKEND_FIR: JVM_IR -// FIR status: failK // TARGET_BACKEND: JVM // JVM_TARGET: 1.8 // WITH_STDLIB diff --git a/compiler/testData/codegen/box/delegation/delegationToMap.kt b/compiler/testData/codegen/box/delegation/delegationToMap.kt index 7552b75f0b6..6dced10fc5a 100644 --- a/compiler/testData/codegen/box/delegation/delegationToMap.kt +++ b/compiler/testData/codegen/box/delegation/delegationToMap.kt @@ -1,5 +1,12 @@ // IGNORE_BACKEND_FIR: JVM_IR -// FIR status: Shouldn't be executed in 'remove' +// FIR status: NSME: Test.remove(Ljava/lang/String;Ljava/lang/String;)Z +// FIR + JVM_IR: +// INVOKEVIRTUAL Test.remove (Ljava/lang/String;Ljava/lang/String;)Z +// => java.lang.NoSuchMethodError: Test.remove(Ljava/lang/String;Ljava/lang/String;)Z +// FE1.0 + JVM_IR: +// INVOKEVIRTUAL Test.remove (Ljava/lang/Object;Ljava/lang/Object;)Z +// => default method in java.util.Map (as expected) + // SKIP_JDK6 // TARGET_BACKEND: JVM // FULL_JDK @@ -25,3 +32,4 @@ fun box(): String { return test.getOrDefault("absent", "OK") } + diff --git a/compiler/testData/codegen/box/jvm8/defaults/allCompatibility/delegationBy/simple.kt b/compiler/testData/codegen/box/jvm8/defaults/allCompatibility/delegationBy/simple.kt index d5fbbcb2d3b..e314dece6ae 100644 --- a/compiler/testData/codegen/box/jvm8/defaults/allCompatibility/delegationBy/simple.kt +++ b/compiler/testData/codegen/box/jvm8/defaults/allCompatibility/delegationBy/simple.kt @@ -1,6 +1,4 @@ // !JVM_DEFAULT_MODE: all-compatibility -// IGNORE_BACKEND_FIR: JVM_IR -// FIR status: failK // TARGET_BACKEND: JVM // JVM_TARGET: 1.8 // WITH_STDLIB diff --git a/compiler/testData/codegen/box/jvm8/defaults/allCompatibility/delegationBy/simpleProperty.kt b/compiler/testData/codegen/box/jvm8/defaults/allCompatibility/delegationBy/simpleProperty.kt index 3c4967f4e44..31bcb780765 100644 --- a/compiler/testData/codegen/box/jvm8/defaults/allCompatibility/delegationBy/simpleProperty.kt +++ b/compiler/testData/codegen/box/jvm8/defaults/allCompatibility/delegationBy/simpleProperty.kt @@ -1,6 +1,4 @@ // !JVM_DEFAULT_MODE: all-compatibility -// IGNORE_BACKEND_FIR: JVM_IR -// FIR status: failK // TARGET_BACKEND: JVM // JVM_TARGET: 1.8 // WITH_STDLIB diff --git a/compiler/testData/codegen/box/jvm8/defaults/delegationBy/javaDefaultMethod.kt b/compiler/testData/codegen/box/jvm8/defaults/delegationBy/javaDefaultMethod.kt new file mode 100644 index 00000000000..49c8d4b9160 --- /dev/null +++ b/compiler/testData/codegen/box/jvm8/defaults/delegationBy/javaDefaultMethod.kt @@ -0,0 +1,24 @@ +// TARGET_BACKEND: JVM +// JVM_TARGET: 1.8 +// WITH_STDLIB + +// FILE: javaDefaultMethod.kt + +class JImpl : J { + override fun getO() = "fail" + override fun getK() = "K" +} + +class Test : J by JImpl() + +fun box() = + Test().getO() + Test().getK() + +// FILE: J.java +public interface J { + default String getO() { + return "O"; + } + + String getK(); +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/jvm8/defaults/delegationBy/simple.kt b/compiler/testData/codegen/box/jvm8/defaults/delegationBy/simple.kt index 7e3cf6eb32e..ac1826a4ff4 100644 --- a/compiler/testData/codegen/box/jvm8/defaults/delegationBy/simple.kt +++ b/compiler/testData/codegen/box/jvm8/defaults/delegationBy/simple.kt @@ -1,6 +1,4 @@ // !JVM_DEFAULT_MODE: enable -// IGNORE_BACKEND_FIR: JVM_IR -// FIR status: failK // TARGET_BACKEND: JVM // JVM_TARGET: 1.8 // WITH_STDLIB diff --git a/compiler/testData/codegen/box/jvm8/defaults/delegationBy/simpleProperty.kt b/compiler/testData/codegen/box/jvm8/defaults/delegationBy/simpleProperty.kt index 907ca4f25dd..68f6b57000c 100644 --- a/compiler/testData/codegen/box/jvm8/defaults/delegationBy/simpleProperty.kt +++ b/compiler/testData/codegen/box/jvm8/defaults/delegationBy/simpleProperty.kt @@ -1,6 +1,4 @@ // !JVM_DEFAULT_MODE: enable -// IGNORE_BACKEND_FIR: JVM_IR -// FIR status: failK // TARGET_BACKEND: JVM // JVM_TARGET: 1.8 // WITH_STDLIB diff --git a/compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/delegationBy/simple.kt b/compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/delegationBy/simple.kt index 3a1e81fe0f1..94b9838e941 100644 --- a/compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/delegationBy/simple.kt +++ b/compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/delegationBy/simple.kt @@ -1,6 +1,4 @@ // !JVM_DEFAULT_MODE: all -// IGNORE_BACKEND_FIR: JVM_IR -// FIR status: failK // TARGET_BACKEND: JVM // JVM_TARGET: 1.8 // WITH_STDLIB diff --git a/compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/delegationBy/simpleProperty.kt b/compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/delegationBy/simpleProperty.kt index d64e4b348e3..3f0736eda50 100644 --- a/compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/delegationBy/simpleProperty.kt +++ b/compiler/testData/codegen/box/jvm8/defaults/noDefaultImpls/delegationBy/simpleProperty.kt @@ -1,6 +1,4 @@ // !JVM_DEFAULT_MODE: all -// IGNORE_BACKEND_FIR: JVM_IR -// FIR status: failK // TARGET_BACKEND: JVM // JVM_TARGET: 1.8 // WITH_STDLIB diff --git a/compiler/testData/ir/irText/firProblems/kt43342.fir.ir.txt b/compiler/testData/ir/irText/firProblems/kt43342.fir.ir.txt index 3cfa9fc0167..1435868ae49 100644 --- a/compiler/testData/ir/irText/firProblems/kt43342.fir.ir.txt +++ b/compiler/testData/ir/irText/firProblems/kt43342.fir.ir.txt @@ -41,22 +41,6 @@ FILE fqName: fileName:/kt43342.kt $this: GET_FIELD 'FIELD DELEGATE name:<$$delegate_0> type:kotlin.collections.Map.ControlFlowInfo, V of .ControlFlowInfo> visibility:local [final]' type=kotlin.collections.Map.ControlFlowInfo, V of .ControlFlowInfo> origin=null receiver: GET_VAR ': .ControlFlowInfo.ControlFlowInfo, V of .ControlFlowInfo> declared in .ControlFlowInfo.get' type=.ControlFlowInfo.ControlFlowInfo, V of .ControlFlowInfo> origin=null key: GET_VAR 'key: K of .ControlFlowInfo declared in .ControlFlowInfo.get' type=K of .ControlFlowInfo origin=null - FUN DELEGATED_MEMBER name:getOrDefault visibility:public modality:OPEN <> ($this:.ControlFlowInfo.ControlFlowInfo, V of .ControlFlowInfo>, key:K of .ControlFlowInfo, defaultValue:V of .ControlFlowInfo) returnType:V of .ControlFlowInfo - annotations: - SinceKotlin(version = '1.1') - PlatformDependent - overridden: - public open fun getOrDefault (key: K of kotlin.collections.Map, defaultValue: V of kotlin.collections.Map): V of kotlin.collections.Map declared in kotlin.collections.Map - $this: VALUE_PARAMETER name: type:.ControlFlowInfo.ControlFlowInfo, V of .ControlFlowInfo> - VALUE_PARAMETER name:key index:0 type:K of .ControlFlowInfo - VALUE_PARAMETER name:defaultValue index:1 type:V of .ControlFlowInfo - BLOCK_BODY - RETURN type=kotlin.Nothing from='public open fun getOrDefault (key: K of .ControlFlowInfo, defaultValue: V of .ControlFlowInfo): V of .ControlFlowInfo declared in .ControlFlowInfo' - CALL 'public open fun getOrDefault (key: K of kotlin.collections.Map, defaultValue: V of kotlin.collections.Map): V of kotlin.collections.Map declared in kotlin.collections.Map' type=V of .ControlFlowInfo origin=null - $this: GET_FIELD 'FIELD DELEGATE name:<$$delegate_0> type:kotlin.collections.Map.ControlFlowInfo, V of .ControlFlowInfo> visibility:local [final]' type=kotlin.collections.Map.ControlFlowInfo, V of .ControlFlowInfo> origin=null - receiver: GET_VAR ': .ControlFlowInfo.ControlFlowInfo, V of .ControlFlowInfo> declared in .ControlFlowInfo.getOrDefault' type=.ControlFlowInfo.ControlFlowInfo, V of .ControlFlowInfo> origin=null - key: GET_VAR 'key: K of .ControlFlowInfo declared in .ControlFlowInfo.getOrDefault' type=K of .ControlFlowInfo origin=null - defaultValue: GET_VAR 'defaultValue: V of .ControlFlowInfo declared in .ControlFlowInfo.getOrDefault' type=V of .ControlFlowInfo origin=null FUN DELEGATED_MEMBER name:isEmpty visibility:public modality:OPEN <> ($this:.ControlFlowInfo.ControlFlowInfo, V of .ControlFlowInfo>) returnType:kotlin.Boolean overridden: public abstract fun isEmpty (): kotlin.Boolean declared in kotlin.collections.Map diff --git a/compiler/testData/ir/irText/firProblems/kt43342.fir.kt.txt b/compiler/testData/ir/irText/firProblems/kt43342.fir.kt.txt index c11a33034fd..5b5b4be2334 100644 --- a/compiler/testData/ir/irText/firProblems/kt43342.fir.kt.txt +++ b/compiler/testData/ir/irText/firProblems/kt43342.fir.kt.txt @@ -17,12 +17,6 @@ open class ControlFlowInfo : Map { return .#<$$delegate_0>.get(key = key) } - @SinceKotlin(version = "1.1") - @PlatformDependent - override fun getOrDefault(key: K, defaultValue: V): V { - return .#<$$delegate_0>.getOrDefault(key = key, defaultValue = defaultValue) - } - override fun isEmpty(): Boolean { return .#<$$delegate_0>.isEmpty() } diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java index dbe9e4b721e..6923029c7cd 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java @@ -24928,6 +24928,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/jvm8/defaults/delegationBy"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true); } + @Test + @TestMetadata("javaDefaultMethod.kt") + public void testJavaDefaultMethod() throws Exception { + runTest("compiler/testData/codegen/box/jvm8/defaults/delegationBy/javaDefaultMethod.kt"); + } + @Test @TestMetadata("simple.kt") public void testSimple() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java index 61c41c25c30..5408bac70b5 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java @@ -25090,6 +25090,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/jvm8/defaults/delegationBy"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); } + @Test + @TestMetadata("javaDefaultMethod.kt") + public void testJavaDefaultMethod() throws Exception { + runTest("compiler/testData/codegen/box/jvm8/defaults/delegationBy/javaDefaultMethod.kt"); + } + @Test @TestMetadata("simple.kt") public void testSimple() throws Exception { diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 480148eb594..fc4d989fa9a 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -20986,6 +20986,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/jvm8/defaults/delegationBy"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true); } + @TestMetadata("javaDefaultMethod.kt") + public void testJavaDefaultMethod() throws Exception { + runTest("compiler/testData/codegen/box/jvm8/defaults/delegationBy/javaDefaultMethod.kt"); + } + @TestMetadata("simple.kt") public void testSimple() throws Exception { runTest("compiler/testData/codegen/box/jvm8/defaults/delegationBy/simple.kt"); diff --git a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeExtBlackBoxTestGenerated.java b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeExtBlackBoxTestGenerated.java index cf8b587673e..c5d37cfc4f7 100644 --- a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeExtBlackBoxTestGenerated.java +++ b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeExtBlackBoxTestGenerated.java @@ -25391,6 +25391,12 @@ public class NativeExtBlackBoxTestGenerated extends AbstractNativeBlackBoxTest { KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/jvm8/defaults/delegationBy"), Pattern.compile("^(.+)\\.kt$"), null, true); } + @Test + @TestMetadata("javaDefaultMethod.kt") + public void testJavaDefaultMethod() throws Exception { + runTest("compiler/testData/codegen/box/jvm8/defaults/delegationBy/javaDefaultMethod.kt"); + } + @Test @TestMetadata("simple.kt") public void testSimple() throws Exception {