JVM_IR: in InheritedDefaultMethodsOnClassesLowering, skip bridges when resolving overrides

This commit is contained in:
Georgy Bronnikov
2020-02-11 17:57:06 +03:00
parent 829e5908d0
commit c71e87068a
9 changed files with 65 additions and 7 deletions
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.backend.common.ir.passTypeArgumentsFrom
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.backend.jvm.codegen.isJvmInterface import org.jetbrains.kotlin.backend.jvm.codegen.isJvmInterface
import org.jetbrains.kotlin.backend.jvm.ir.createDelegatingCallWithPlaceholderTypeArguments import org.jetbrains.kotlin.backend.jvm.ir.createDelegatingCallWithPlaceholderTypeArguments
import org.jetbrains.kotlin.backend.jvm.ir.createPlaceholderAnyNType import org.jetbrains.kotlin.backend.jvm.ir.createPlaceholderAnyNType
@@ -219,15 +220,23 @@ private class InterfaceObjectCallsLowering(val context: JvmBackendContext) : IrE
* interface implementation should be generated into the class containing the fake override; or null if the given function is not a fake * interface implementation should be generated into the class containing the fake override; or null if the given function is not a fake
* override of any interface implementation or such method was already generated into the superclass or is a method from Any. * override of any interface implementation or such method was already generated into the superclass or is a method from Any.
*/ */
private fun isDefaultImplsBridge(f: IrSimpleFunction) =
f.origin == JvmLoweredDeclarationOrigin.DEFAULT_IMPLS_BRIDGE ||
f.origin == JvmLoweredDeclarationOrigin.DEFAULT_IMPLS_BRIDGE_TO_SYNTHETIC
internal fun IrSimpleFunction.findInterfaceImplementation(): IrSimpleFunction? { internal fun IrSimpleFunction.findInterfaceImplementation(): IrSimpleFunction? {
if (!isFakeOverride) return null if (!isFakeOverride) return null
parent.let { if (it is IrClass && it.isJvmInterface) return null } parent.let { if (it is IrClass && it.isJvmInterface) return null }
val implementation = resolveFakeOverride() ?: return null val implementation = resolveFakeOverride(toSkip = ::isDefaultImplsBridge) ?: return null
// Only generate interface delegation for functions immediately inherited from an interface. // Only generate interface delegation for functions immediately inherited from an interface.
// (Otherwise, delegation will be present in the parent class) // (Otherwise, delegation will be present in the parent class)
if (overriddenSymbols.any { !it.owner.parentAsClass.isInterface && it.owner.modality != Modality.ABSTRACT && it.owner.resolveFakeOverride() == implementation }) { if (overriddenSymbols.any {
!it.owner.parentAsClass.isInterface &&
it.owner.modality != Modality.ABSTRACT &&
it.owner.resolveFakeOverride(toSkip = ::isDefaultImplsBridge) == implementation
}) {
return null return null
} }
@@ -260,8 +260,8 @@ fun IrClass.isSubclassOf(ancestor: IrClass): Boolean {
return this.hasAncestorInSuperTypes() return this.hasAncestorInSuperTypes()
} }
fun IrSimpleFunction.collectRealOverrides(): Set<IrSimpleFunction> { fun IrSimpleFunction.collectRealOverrides(toSkip: (IrSimpleFunction) -> Boolean = { false }): Set<IrSimpleFunction> {
if (isReal) return setOf(this) if (isReal && !toSkip(this)) return setOf(this)
val visited = mutableSetOf<IrSimpleFunction>() val visited = mutableSetOf<IrSimpleFunction>()
val realOverrides = mutableSetOf<IrSimpleFunction>() val realOverrides = mutableSetOf<IrSimpleFunction>()
@@ -269,7 +269,7 @@ fun IrSimpleFunction.collectRealOverrides(): Set<IrSimpleFunction> {
fun collectRealOverrides(func: IrSimpleFunction) { fun collectRealOverrides(func: IrSimpleFunction) {
if (!visited.add(func)) return if (!visited.add(func)) return
if (func.isReal) { if (func.isReal && !toSkip(func)) {
realOverrides += func realOverrides += func
} else { } else {
func.overriddenSymbols.forEach { collectRealOverrides(it.owner) } func.overriddenSymbols.forEach { collectRealOverrides(it.owner) }
@@ -295,8 +295,8 @@ fun IrSimpleFunction.collectRealOverrides(): Set<IrSimpleFunction> {
// This implementation is from kotlin-native // This implementation is from kotlin-native
// TODO: use this implementation instead of any other // TODO: use this implementation instead of any other
fun IrSimpleFunction.resolveFakeOverride(): IrSimpleFunction? { fun IrSimpleFunction.resolveFakeOverride(toSkip: (IrSimpleFunction) -> Boolean = { false }): IrSimpleFunction? {
return collectRealOverrides().singleOrNull { it.modality != Modality.ABSTRACT } return collectRealOverrides(toSkip).singleOrNull { it.modality != Modality.ABSTRACT }
} }
fun IrSimpleFunction.isOrOverridesSynthesized(): Boolean { fun IrSimpleFunction.isOrOverridesSynthesized(): Boolean {
+19
View File
@@ -0,0 +1,19 @@
// IGNORE_BACKEND_FIR: JVM_IR
interface A {
val result: String get() = "Fail"
}
interface B : A
abstract class AImpl : A
abstract class BImpl : AImpl(), B
interface C : B {
override val result: String get() = "OK"
}
object CImpl : BImpl(), C
fun box(): String = CImpl.result
@@ -28052,6 +28052,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/traits/diamondPropertyAccessors.kt"); runTest("compiler/testData/codegen/box/traits/diamondPropertyAccessors.kt");
} }
@TestMetadata("doubleDiamond.kt")
public void testDoubleDiamond() throws Exception {
runTest("compiler/testData/codegen/box/traits/doubleDiamond.kt");
}
@TestMetadata("genericMethod.kt") @TestMetadata("genericMethod.kt")
public void testGenericMethod() throws Exception { public void testGenericMethod() throws Exception {
runTest("compiler/testData/codegen/box/traits/genericMethod.kt"); runTest("compiler/testData/codegen/box/traits/genericMethod.kt");
@@ -26869,6 +26869,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/traits/diamondPropertyAccessors.kt"); runTest("compiler/testData/codegen/box/traits/diamondPropertyAccessors.kt");
} }
@TestMetadata("doubleDiamond.kt")
public void testDoubleDiamond() throws Exception {
runTest("compiler/testData/codegen/box/traits/doubleDiamond.kt");
}
@TestMetadata("genericMethod.kt") @TestMetadata("genericMethod.kt")
public void testGenericMethod() throws Exception { public void testGenericMethod() throws Exception {
runTest("compiler/testData/codegen/box/traits/genericMethod.kt"); runTest("compiler/testData/codegen/box/traits/genericMethod.kt");
@@ -26556,6 +26556,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/traits/diamondPropertyAccessors.kt"); runTest("compiler/testData/codegen/box/traits/diamondPropertyAccessors.kt");
} }
@TestMetadata("doubleDiamond.kt")
public void testDoubleDiamond() throws Exception {
runTest("compiler/testData/codegen/box/traits/doubleDiamond.kt");
}
@TestMetadata("genericMethod.kt") @TestMetadata("genericMethod.kt")
public void testGenericMethod() throws Exception { public void testGenericMethod() throws Exception {
runTest("compiler/testData/codegen/box/traits/genericMethod.kt"); runTest("compiler/testData/codegen/box/traits/genericMethod.kt");
@@ -26556,6 +26556,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/traits/diamondPropertyAccessors.kt"); runTest("compiler/testData/codegen/box/traits/diamondPropertyAccessors.kt");
} }
@TestMetadata("doubleDiamond.kt")
public void testDoubleDiamond() throws Exception {
runTest("compiler/testData/codegen/box/traits/doubleDiamond.kt");
}
@TestMetadata("genericMethod.kt") @TestMetadata("genericMethod.kt")
public void testGenericMethod() throws Exception { public void testGenericMethod() throws Exception {
runTest("compiler/testData/codegen/box/traits/genericMethod.kt"); runTest("compiler/testData/codegen/box/traits/genericMethod.kt");
@@ -21567,6 +21567,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/traits/diamondPropertyAccessors.kt"); runTest("compiler/testData/codegen/box/traits/diamondPropertyAccessors.kt");
} }
@TestMetadata("doubleDiamond.kt")
public void testDoubleDiamond() throws Exception {
runTest("compiler/testData/codegen/box/traits/doubleDiamond.kt");
}
@TestMetadata("genericMethod.kt") @TestMetadata("genericMethod.kt")
public void testGenericMethod() throws Exception { public void testGenericMethod() throws Exception {
runTest("compiler/testData/codegen/box/traits/genericMethod.kt"); runTest("compiler/testData/codegen/box/traits/genericMethod.kt");
@@ -21627,6 +21627,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/traits/diamondPropertyAccessors.kt"); runTest("compiler/testData/codegen/box/traits/diamondPropertyAccessors.kt");
} }
@TestMetadata("doubleDiamond.kt")
public void testDoubleDiamond() throws Exception {
runTest("compiler/testData/codegen/box/traits/doubleDiamond.kt");
}
@TestMetadata("genericMethod.kt") @TestMetadata("genericMethod.kt")
public void testGenericMethod() throws Exception { public void testGenericMethod() throws Exception {
runTest("compiler/testData/codegen/box/traits/genericMethod.kt"); runTest("compiler/testData/codegen/box/traits/genericMethod.kt");