@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
99import org.jetbrains.kotlin.backend.common.lower.parents
1010import org.jetbrains.kotlin.backend.common.pop
1111import org.jetbrains.kotlin.builtins.functions.BuiltInFunctionArity
12+ import org.jetbrains.kotlin.config.JvmAnalysisFlags
1213import org.jetbrains.kotlin.descriptors.*
1314import org.jetbrains.kotlin.descriptors.java.JavaVisibilities
1415import org.jetbrains.kotlin.ir.IrElement
@@ -845,10 +846,68 @@ open class KotlinFileExtractor(
845846 }
846847 }
847848
849+ private fun isKotlinDefinedInterface (cls : IrClass ? ) =
850+ cls != null && cls.isInterface && cls.origin != IrDeclarationOrigin .IR_EXTERNAL_JAVA_DECLARATION_STUB
851+
852+ private fun needsInterfaceForwarder (f : IrFunction ) =
853+ // 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.
854+ // Otherwise, for a Kotlin-defined method inheriting a Kotlin-defined default, we need to create a synthetic method like
855+ // `int f(int x) { return super.InterfaceWithDefault.f(x); }`, because kotlinc will generate a public method and Java callers may directly target it.
856+ // (NB. kotlinc's actual implementation strategy is different -- it makes an inner class called InterfaceWithDefault$DefaultImpls and stores the default methods
857+ // there to allow default method usage in Java < 8, but this is hopefully niche.
858+ ! pluginContext.languageVersionSettings.getFlag(JvmAnalysisFlags .jvmDefaultMode).forAllMethodsWithBody &&
859+ f.parentClassOrNull.let { it != null && it.origin != IrDeclarationOrigin .IR_EXTERNAL_JAVA_DECLARATION_STUB && it.modality != Modality .ABSTRACT } &&
860+ f.realOverrideTarget.let { it != f && (it as ? IrSimpleFunction )?.modality != Modality .ABSTRACT && isKotlinDefinedInterface(it.parentClassOrNull) }
861+
862+ private fun makeInterfaceForwarder (f : IrFunction , parentId : Label <out DbReftype >, extractBody : Boolean , extractMethodAndParameterTypeAccesses : Boolean , typeSubstitution : TypeSubstitution ? , classTypeArgsIncludingOuterClasses : List <IrTypeArgument >? ) =
863+ forceExtractFunction(f, parentId, extractBody = false , extractMethodAndParameterTypeAccesses, typeSubstitution, classTypeArgsIncludingOuterClasses, overriddenAttributes = OverriddenFunctionAttributes (visibility = DescriptorVisibilities .PUBLIC )).also { functionId ->
864+ tw.writeCompiler_generated(functionId, CompilerGeneratedKinds .INTERFACE_FORWARDER .kind)
865+ if (extractBody) {
866+ val realFunctionLocId = tw.getLocation(f)
867+ val inheritedDefaultFunction = f.realOverrideTarget
868+ val directlyInheritedSymbol =
869+ when (f) {
870+ is IrSimpleFunction ->
871+ f.overriddenSymbols.find { it.owner == = inheritedDefaultFunction }
872+ ? : f.overriddenSymbols.find { it.owner.realOverrideTarget == = inheritedDefaultFunction }
873+ ? : inheritedDefaultFunction.symbol
874+ else -> inheritedDefaultFunction.symbol // This is strictly invalid, since we shouldn't use A.super.f(...) where A may not be a direct supertype, but this path should also be unreachable.
875+ }
876+ val defaultDefiningInterfaceType = (directlyInheritedSymbol.owner.parentClassOrNull ? : return functionId).typeWith()
877+
878+ extractExpressionBody(functionId, realFunctionLocId).also { returnId ->
879+ extractRawMethodAccess(
880+ f,
881+ realFunctionLocId,
882+ f.returnType,
883+ functionId,
884+ returnId,
885+ 0 ,
886+ returnId,
887+ f.valueParameters.size,
888+ { argParentId, idxOffset ->
889+ f.valueParameters.mapIndexed { idx, param ->
890+ val syntheticParamId = useValueParameter(param, functionId)
891+ extractVariableAccess(syntheticParamId, param.type, realFunctionLocId, argParentId, idxOffset + idx, functionId, returnId)
892+ }
893+ },
894+ f.dispatchReceiverParameter?.type,
895+ { callId ->
896+ extractSuperAccess(defaultDefiningInterfaceType, functionId, callId, - 1 , returnId, realFunctionLocId)
897+ },
898+ null
899+ )
900+ }
901+ }
902+ }
903+
848904 private fun extractFunction (f : IrFunction , parentId : Label <out DbReftype >, extractBody : Boolean , extractMethodAndParameterTypeAccesses : Boolean , typeSubstitution : TypeSubstitution ? , classTypeArgsIncludingOuterClasses : List <IrTypeArgument >? ) =
849- if (isFake(f))
850- null
851- else {
905+ if (isFake(f)) {
906+ if (needsInterfaceForwarder(f))
907+ makeInterfaceForwarder(f, parentId, extractBody, extractMethodAndParameterTypeAccesses, typeSubstitution, classTypeArgsIncludingOuterClasses)
908+ else
909+ null
910+ } else {
852911 forceExtractFunction(f, parentId, extractBody, extractMethodAndParameterTypeAccesses, typeSubstitution, classTypeArgsIncludingOuterClasses).also {
853912 // The defaults-forwarder function is a static utility, not a member, so we only need to extract this for the unspecialised instance of this class.
854913 if (classTypeArgsIncludingOuterClasses.isNullOrEmpty())
@@ -1163,7 +1222,7 @@ open class KotlinFileExtractor(
11631222 extractBody(body, id)
11641223 }
11651224
1166- extractVisibility(f, id, f.visibility)
1225+ extractVisibility(f, id, overriddenAttributes?.visibility ? : f.visibility)
11671226
11681227 if (f.isInline) {
11691228 addModifiers(id, " inline" )
@@ -1227,7 +1286,9 @@ open class KotlinFileExtractor(
12271286
12281287 private fun extractProperty (p : IrProperty , parentId : Label <out DbReftype >, extractBackingField : Boolean , extractFunctionBodies : Boolean , extractPrivateMembers : Boolean , typeSubstitution : TypeSubstitution ? , classTypeArgsIncludingOuterClasses : List <IrTypeArgument >? ) {
12291288 with (" property" , p) {
1230- if (isFake(p)) return
1289+ fun needsInterfaceForwarderQ (f : IrFunction ? ) = f?.let { needsInterfaceForwarder(f) } ? : false
1290+
1291+ if (isFake(p) && ! needsInterfaceForwarderQ(p.getter) && ! needsInterfaceForwarderQ(p.setter)) return
12311292
12321293 DeclarationStackAdjuster (p).use {
12331294
@@ -5375,7 +5436,9 @@ open class KotlinFileExtractor(
53755436 val sourceLoc : Label <DbLocation >? = null ,
53765437 val valueParameters : List <IrValueParameter >? = null ,
53775438 val typeParameters : List <IrTypeParameter >? = null ,
5378- val isStatic : Boolean? = null )
5439+ val isStatic : Boolean? = null ,
5440+ val visibility : DescriptorVisibility ? = null ,
5441+ )
53795442
53805443 private fun peekDeclStackAsDeclarationParent (elementToReportOn : IrElement ): IrDeclarationParent ? {
53815444 val trapWriter = tw
@@ -5400,6 +5463,7 @@ open class KotlinFileExtractor(
54005463 DELEGATED_PROPERTY_SETTER (7 ),
54015464 JVMSTATIC_PROXY_METHOD (8 ),
54025465 JVMOVERLOADS_METHOD (9 ),
5403- DEFAULT_ARGUMENTS_METHOD (10 )
5466+ DEFAULT_ARGUMENTS_METHOD (10 ),
5467+ INTERFACE_FORWARDER (11 ),
54045468 }
54055469}
0 commit comments