@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
9
9
import org.jetbrains.kotlin.backend.common.lower.parents
10
10
import org.jetbrains.kotlin.backend.common.pop
11
11
import org.jetbrains.kotlin.builtins.functions.BuiltInFunctionArity
12
+ import org.jetbrains.kotlin.config.JvmAnalysisFlags
12
13
import org.jetbrains.kotlin.descriptors.*
13
14
import org.jetbrains.kotlin.descriptors.java.JavaVisibilities
14
15
import org.jetbrains.kotlin.ir.IrElement
@@ -845,10 +846,68 @@ open class KotlinFileExtractor(
845
846
}
846
847
}
847
848
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
+
848
904
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 {
852
911
forceExtractFunction(f, parentId, extractBody, extractMethodAndParameterTypeAccesses, typeSubstitution, classTypeArgsIncludingOuterClasses).also {
853
912
// 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.
854
913
if (classTypeArgsIncludingOuterClasses.isNullOrEmpty())
@@ -1163,7 +1222,7 @@ open class KotlinFileExtractor(
1163
1222
extractBody(body, id)
1164
1223
}
1165
1224
1166
- extractVisibility(f, id, f.visibility)
1225
+ extractVisibility(f, id, overriddenAttributes?.visibility ? : f.visibility)
1167
1226
1168
1227
if (f.isInline) {
1169
1228
addModifiers(id, " inline" )
@@ -1227,7 +1286,9 @@ open class KotlinFileExtractor(
1227
1286
1228
1287
private fun extractProperty (p : IrProperty , parentId : Label <out DbReftype >, extractBackingField : Boolean , extractFunctionBodies : Boolean , extractPrivateMembers : Boolean , typeSubstitution : TypeSubstitution ? , classTypeArgsIncludingOuterClasses : List <IrTypeArgument >? ) {
1229
1288
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
1231
1292
1232
1293
DeclarationStackAdjuster (p).use {
1233
1294
@@ -5375,7 +5436,9 @@ open class KotlinFileExtractor(
5375
5436
val sourceLoc : Label <DbLocation >? = null ,
5376
5437
val valueParameters : List <IrValueParameter >? = null ,
5377
5438
val typeParameters : List <IrTypeParameter >? = null ,
5378
- val isStatic : Boolean? = null )
5439
+ val isStatic : Boolean? = null ,
5440
+ val visibility : DescriptorVisibility ? = null ,
5441
+ )
5379
5442
5380
5443
private fun peekDeclStackAsDeclarationParent (elementToReportOn : IrElement ): IrDeclarationParent ? {
5381
5444
val trapWriter = tw
@@ -5400,6 +5463,7 @@ open class KotlinFileExtractor(
5400
5463
DELEGATED_PROPERTY_SETTER (7 ),
5401
5464
JVMSTATIC_PROXY_METHOD (8 ),
5402
5465
JVMOVERLOADS_METHOD (9 ),
5403
- DEFAULT_ARGUMENTS_METHOD (10 )
5466
+ DEFAULT_ARGUMENTS_METHOD (10 ),
5467
+ INTERFACE_FORWARDER (11 ),
5404
5468
}
5405
5469
}
0 commit comments