FIR2IR don't generate delegates for default interface members

This commit is contained in:
Dmitry Petrov
2021-11-24 17:33:51 +03:00
committed by TeamCityServer
parent 261482904c
commit 88f41d006a
19 changed files with 97 additions and 47 deletions
@@ -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<IrFunction, List<FirNamedFunctionSymbol>>()
private val basePropertySymbols = mutableMapOf<IrProperty, List<FirPropertySymbol>>()
@@ -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 }
@@ -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 {
@@ -59,12 +59,6 @@ inline val <reified D : FirCallableDeclaration> D.baseForIntersectionOverride: D
inline val <reified S : FirCallableSymbol<*>> 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 <reified D : FirCallableDeclaration> D.originalIfFakeOverride(): D? =
originalForSubstitutionOverride ?: baseForIntersectionOverride
@@ -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
@@ -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
@@ -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")
}
@@ -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
@@ -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
@@ -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();
}
@@ -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
@@ -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
@@ -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
@@ -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
@@ -41,22 +41,6 @@ FILE fqName:<root> fileName:/kt43342.kt
$this: GET_FIELD 'FIELD DELEGATE name:<$$delegate_0> type:kotlin.collections.Map<K of <root>.ControlFlowInfo, V of <root>.ControlFlowInfo> visibility:local [final]' type=kotlin.collections.Map<K of <root>.ControlFlowInfo, V of <root>.ControlFlowInfo> origin=null
receiver: GET_VAR '<this>: <root>.ControlFlowInfo<K of <root>.ControlFlowInfo, V of <root>.ControlFlowInfo> declared in <root>.ControlFlowInfo.get' type=<root>.ControlFlowInfo<K of <root>.ControlFlowInfo, V of <root>.ControlFlowInfo> origin=null
key: GET_VAR 'key: K of <root>.ControlFlowInfo declared in <root>.ControlFlowInfo.get' type=K of <root>.ControlFlowInfo origin=null
FUN DELEGATED_MEMBER name:getOrDefault visibility:public modality:OPEN <> ($this:<root>.ControlFlowInfo<K of <root>.ControlFlowInfo, V of <root>.ControlFlowInfo>, key:K of <root>.ControlFlowInfo, defaultValue:V of <root>.ControlFlowInfo) returnType:V of <root>.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:<this> type:<root>.ControlFlowInfo<K of <root>.ControlFlowInfo, V of <root>.ControlFlowInfo>
VALUE_PARAMETER name:key index:0 type:K of <root>.ControlFlowInfo
VALUE_PARAMETER name:defaultValue index:1 type:V of <root>.ControlFlowInfo
BLOCK_BODY
RETURN type=kotlin.Nothing from='public open fun getOrDefault (key: K of <root>.ControlFlowInfo, defaultValue: V of <root>.ControlFlowInfo): V of <root>.ControlFlowInfo declared in <root>.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 <root>.ControlFlowInfo origin=null
$this: GET_FIELD 'FIELD DELEGATE name:<$$delegate_0> type:kotlin.collections.Map<K of <root>.ControlFlowInfo, V of <root>.ControlFlowInfo> visibility:local [final]' type=kotlin.collections.Map<K of <root>.ControlFlowInfo, V of <root>.ControlFlowInfo> origin=null
receiver: GET_VAR '<this>: <root>.ControlFlowInfo<K of <root>.ControlFlowInfo, V of <root>.ControlFlowInfo> declared in <root>.ControlFlowInfo.getOrDefault' type=<root>.ControlFlowInfo<K of <root>.ControlFlowInfo, V of <root>.ControlFlowInfo> origin=null
key: GET_VAR 'key: K of <root>.ControlFlowInfo declared in <root>.ControlFlowInfo.getOrDefault' type=K of <root>.ControlFlowInfo origin=null
defaultValue: GET_VAR 'defaultValue: V of <root>.ControlFlowInfo declared in <root>.ControlFlowInfo.getOrDefault' type=V of <root>.ControlFlowInfo origin=null
FUN DELEGATED_MEMBER name:isEmpty visibility:public modality:OPEN <> ($this:<root>.ControlFlowInfo<K of <root>.ControlFlowInfo, V of <root>.ControlFlowInfo>) returnType:kotlin.Boolean
overridden:
public abstract fun isEmpty (): kotlin.Boolean declared in kotlin.collections.Map
@@ -17,12 +17,6 @@ open class ControlFlowInfo<K : Any?, V : Any?> : Map<K, V> {
return <this>.#<$$delegate_0>.get(key = key)
}
@SinceKotlin(version = "1.1")
@PlatformDependent
override fun getOrDefault(key: K, defaultValue: V): V {
return <this>.#<$$delegate_0>.getOrDefault(key = key, defaultValue = defaultValue)
}
override fun isEmpty(): Boolean {
return <this>.#<$$delegate_0>.isEmpty()
}
@@ -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 {
@@ -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 {
@@ -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");
@@ -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 {