JVM IR: do not generate DefaultImpls delegate for collection fake overrides

In the newly added test, prior to this change, JVM IR was generating
DefaultImpls classes with calls to things like
`kotlin/collections/MutableList$DefaultImpls.spliterator` and other
default methods present in JDK 8+. This obviously didn't make much
sense. Although these weren't explicitly mentioned anywhere in the
bytecode, they caused some validation tools to report errors (e.g.
animalsniffer used in arrow).
This commit is contained in:
Alexander Udalov
2020-05-14 22:18:03 +02:00
parent 47c25982b6
commit 5647a935a2
9 changed files with 178 additions and 15 deletions
@@ -156,6 +156,7 @@ fun IrSimpleFunction.isCompiledToJvmDefault(jvmDefaultMode: JvmDefaultMode): Boo
assert(!isFakeOverride && parentAsClass.isInterface && modality != Modality.ABSTRACT) {
"`isCompiledToJvmDefault` should be called on non-fakeoverrides and non-abstract methods from interfaces ${ir2string(this)}"
}
if (origin == IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB) return false
if (hasJvmDefault()) return true
val parentDescriptor = propertyIfAccessor.parentAsClass.descriptor
if (parentDescriptor !is DeserializedClassDescriptor) return jvmDefaultMode.forAllMethodsWithBody
@@ -171,19 +171,21 @@ private class InterfaceDefaultCallsLowering(val context: JvmBackendContext) : Ir
}
}
private fun IrSimpleFunction.isDefinitelyNotDefaultImplsMethod(jvmDefaultMode: JvmDefaultMode): Boolean {
if (resolveFakeOverride()?.run {
origin == IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB || isCompiledToJvmDefault(
jvmDefaultMode
)
} != false) return true
return origin == IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER ||
internal fun IrSimpleFunction.isDefinitelyNotDefaultImplsMethod(
jvmDefaultMode: JvmDefaultMode,
implementation: IrSimpleFunction? = resolveFakeOverride()
): Boolean =
implementation == null ||
implementation.origin == IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB ||
implementation.isCompiledToJvmDefault(jvmDefaultMode) ||
origin == IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER ||
hasAnnotation(PLATFORM_DEPENDENT_ANNOTATION_FQ_NAME) ||
(name.asString() == "clone" &&
parent.safeAs<IrClass>()?.fqNameWhenAvailable?.asString() == "kotlin.Cloneable" &&
valueParameters.isEmpty())
}
isCloneableClone()
private fun IrSimpleFunction.isCloneableClone(): Boolean =
name.asString() == "clone" &&
parent.safeAs<IrClass>()?.fqNameWhenAvailable?.asString() == "kotlin.Cloneable" &&
valueParameters.isEmpty()
internal val interfaceObjectCallsPhase = makeIrFilePhase(
lowering = ::InterfaceObjectCallsLowering,
@@ -105,18 +105,17 @@ internal class InterfaceLowering(val context: JvmBackendContext) : IrElementTran
when {
Visibilities.isPrivate(implementation.visibility) || implementation.isMethodOfAny() ->
continue@loop
!implementation.isCompiledToJvmDefault(jvmDefaultMode) -> {
!function.isDefinitelyNotDefaultImplsMethod(jvmDefaultMode, implementation) -> {
val defaultImpl = createDefaultImpl(function)
val superImpl = firstSuperMethodFromKotlin(function, implementation)
context.declarationFactory.getDefaultImplsFunction(superImpl.owner).also {
defaultImpl.bridgeToStatic(it)
}
}
jvmDefaultMode.isCompatibility -> {
jvmDefaultMode.isCompatibility && implementation.isCompiledToJvmDefault(jvmDefaultMode) -> {
val defaultImpl = createDefaultImpl(function)
defaultImpl.bridgeViaAccessorTo(function)
}
// else -> Do nothing.
}
}