Skip to content

Commit 4201031

Browse files
committed
Restrict interface override synthesis to cases where both the overriding class and the interface are Kotlin-defined.
If the interface is Java-defined and it provides a default interface implementation then real class-file default methods are being used and kotlinc won't synthesise anything. If the loaded .class file wasn't made by Kotlin, then we see all the real methods and there is no need to synthesise anything either.
1 parent e8a3598 commit 4201031

File tree

1 file changed

+7
-3
lines changed

1 file changed

+7
-3
lines changed

java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -829,14 +829,18 @@ open class KotlinFileExtractor(
829829
}
830830
}
831831

832+
private fun isKotlinDefinedInterface(cls: IrClass?) =
833+
cls != null && cls.isInterface && cls.origin != IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB
834+
832835
private fun needsInterfaceForwarder(f: IrFunction) =
833836
// forAllMethodsWithBody means -Xjvm-default=all or all-compatibility, in which case real Java default interfaces are used, and we don't need to do anything.
834-
// Otherwise, for a method inheriting a default, we need to create a synthetic method like `int f(int x) { return super.InterfaceWithDefault.f(x); }`, because
835-
// kotlinc will generate a public method and Java callers may directly target it.
837+
// Otherwise, for a Kotlin-defined method inheriting a Kotlin-defined default, we need to create a synthetic method like
838+
// `int f(int x) { return super.InterfaceWithDefault.f(x); }`, because kotlinc will generate a public method and Java callers may directly target it.
836839
// (NB. kotlinc's actual implementation strategy is different -- it makes an inner class called InterfaceWithDefault$DefaultImpls and stores the default methods
837840
// there to allow default method usage in Java < 8, but this is hopefully niche.
838841
!pluginContext.languageVersionSettings.getFlag(JvmAnalysisFlags.jvmDefaultMode).forAllMethodsWithBody &&
839-
f.realOverrideTarget.let { it != f && it.parentClassOrNull?.isInterface == true }
842+
f.parentClassOrNull?.origin != IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB &&
843+
f.realOverrideTarget.let { it != f && isKotlinDefinedInterface(it.parentClassOrNull) }
840844

841845
private fun makeInterfaceForwarder(f: IrFunction, parentId: Label<out DbReftype>, extractBody: Boolean, extractMethodAndParameterTypeAccesses: Boolean, typeSubstitution: TypeSubstitution?, classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?) =
842846
forceExtractFunction(f, parentId, extractBody = false, extractMethodAndParameterTypeAccesses, typeSubstitution, classTypeArgsIncludingOuterClasses).also { functionId ->

0 commit comments

Comments
 (0)