JVM.IR. Add assertions for JVM defaults checks

This commit is contained in:
Mikhail Bogdanov
2020-03-30 09:29:45 +02:00
parent b787c8c011
commit 261af10019
5 changed files with 35 additions and 15 deletions
@@ -53,6 +53,11 @@ fun CallableMemberDescriptor.isCompiledToJvmDefaultIfNoAbstract(jvmDefault: JvmD
val clazz = directMember.containingDeclaration
// TODO add checks after fixes in diagnostics
// assert(this.kind.isReal && isInterface(clazz) && modality != Modality.ABSTRACT) {
// "`isCompiledToJvmDefault` should be called on non-fakeoverrides and non-abstract methods from interfaces $this"
// }
if (directMember.annotations.hasAnnotation(JVM_DEFAULT_FQ_NAME)) return true
if (clazz !is DeserializedClassDescriptor) return jvmDefault.forAllMethodsWithBody
return JvmProtoBufUtil.isNewPlaceForBodyGeneration(clazz.classProto)
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.backend.jvm.ir
import org.jetbrains.kotlin.backend.common.ir.ir2string
import org.jetbrains.kotlin.backend.common.lower.IrLoweringContext
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
@@ -147,10 +148,17 @@ fun IrDeclaration.getJvmNameFromAnnotation(): String? {
val IrFunction.propertyIfAccessor: IrDeclaration
get() = (this as? IrSimpleFunction)?.correspondingPropertySymbol?.owner ?: this
fun IrFunction.isCompiledToJvmDefault(jvmDefaultMode: JvmDefaultMode): Boolean {
fun IrFunction.isSimpleFunctionCompiledToJvmDefault(jvmDefaultMode: JvmDefaultMode): Boolean {
return (this as? IrSimpleFunction)?.isCompiledToJvmDefault(jvmDefaultMode) == true
}
fun IrSimpleFunction.isCompiledToJvmDefault(jvmDefaultMode: JvmDefaultMode): Boolean {
assert(!isFakeOverride && parentAsClass.isInterface && modality != Modality.ABSTRACT) {
"`isCompiledToJvmDefault` should be called on non-fakeoverrides and non-abstract methods from interfaces ${ir2string(this)}"
}
if (hasJvmDefault()) return true
val parentDescriptor = propertyIfAccessor.parentAsClass.descriptor
if (parentDescriptor !is DeserializedClassDescriptor) return jvmDefaultMode.forAllMehtodsWithBody
if (parentDescriptor !is DeserializedClassDescriptor) return jvmDefaultMode.forAllMethodsWithBody
return JvmProtoBufUtil.isNewPlaceForBodyGeneration(parentDescriptor.classProto)
}
@@ -286,10 +294,13 @@ fun IrFunctionAccessExpression.copyFromWithPlaceholderTypeArguments(existingCall
// Check whether a function maps to an abstract method.
// For non-interface methods or interface methods coming from Java the modality is correct. Kotlin interface methods
// are abstract unless they are annotated with @JvmDefault or @PlatformDependent or they override a method with
// such an annotation.
fun IrSimpleFunction.isJvmAbstract(jvmDefaultMode: JvmDefaultMode): Boolean = (modality == Modality.ABSTRACT) ||
(parentAsClass.isJvmInterface && resolveFakeOverride()?.run { !isCompiledToJvmDefault(jvmDefaultMode) && !hasPlatformDependent() } ?: true)
// are abstract unless they are annotated @PlatformDependent or compiled to JVM default (with @JvmDefault annotation or without)
// or they override such method.
fun IrSimpleFunction.isJvmAbstract(jvmDefaultMode: JvmDefaultMode): Boolean {
if (modality == Modality.ABSTRACT) return true
if (!parentAsClass.isJvmInterface) return false
return resolveFakeOverride()?.run { !isCompiledToJvmDefault(jvmDefaultMode) && !hasPlatformDependent() } != false
}
fun firstSuperMethodFromKotlin(
override: IrSimpleFunction,
@@ -153,7 +153,7 @@ private class InterfaceDefaultCallsLowering(val context: JvmBackendContext) : Ir
if (!callee.hasInterfaceParent() ||
callee.origin != IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER ||
callee.isCompiledToJvmDefault(context.state.jvmDefaultMode)
callee.isSimpleFunctionCompiledToJvmDefault(context.state.jvmDefaultMode)
) {
return super.visitCall(expression)
}
@@ -171,14 +171,19 @@ private class InterfaceDefaultCallsLowering(val context: JvmBackendContext) : Ir
}
}
private fun IrSimpleFunction.isDefinitelyNotDefaultImplsMethod(jvmDefaultMode: JvmDefaultMode) =
resolveFakeOverride()?.origin == IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB ||
origin == IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER ||
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 ||
hasAnnotation(PLATFORM_DEPENDENT_ANNOTATION_FQ_NAME) ||
isCompiledToJvmDefault(jvmDefaultMode) ||
(name.asString() == "clone" &&
parent.safeAs<IrClass>()?.fqNameWhenAvailable?.asString() == "kotlin.Cloneable" &&
valueParameters.isEmpty())
}
internal val interfaceObjectCallsPhase = makeIrFilePhase(
lowering = ::InterfaceObjectCallsLowering,
@@ -23,7 +23,6 @@ import org.jetbrains.kotlin.ir.expressions.IrReturn
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrLocalDelegatedPropertySymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.types.defaultType
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
@@ -78,7 +77,7 @@ internal class InterfaceLowering(val context: JvmBackendContext) : IrElementTran
* - the implementation is private, or belongs to java.lang.Object,
* or is a stub for function with default parameters ($default)
* - we're in -Xjvm-default=compatibility|all-compatibility mode, in which case we go via
* accessors on the parent class rather than the DefaultImpls if inherited method compiled to JVM default
* accessors on the parent class rather than the DefaultImpls if inherited method is compiled to JVM default
* - we're in -Xjvm-default=enable|all mode, and we have that default implementation,
* in which case we simply leave it.
*
@@ -493,7 +493,7 @@ internal class SyntheticAccessorLowering(val context: JvmBackendContext) : IrEle
}
}
private fun IrFunction.accessorName(superQualifier: IrClassSymbol?): Name {
private fun IrSimpleFunction.accessorName(superQualifier: IrClassSymbol?): Name {
val jvmName = context.methodSignatureMapper.mapFunctionName(this)
val suffix = when {
// Accessors for top level functions never need a suffix.
@@ -501,7 +501,7 @@ internal class SyntheticAccessorLowering(val context: JvmBackendContext) : IrEle
// The only function accessors placed on interfaces are for private functions and JvmDefault implementations.
// The two cannot clash.
parentAsClass.isJvmInterface -> if (!Visibilities.isPrivate(visibility) && isCompiledToJvmDefault(context.state.jvmDefaultMode)) "\$jd" else ""
parentAsClass.isJvmInterface -> if (!Visibilities.isPrivate(visibility)) "\$jd" else ""
// Accessor for _s_uper-qualified call
superQualifier != null -> "\$s" + superQualifier.descriptor.syntheticAccessorToSuperSuffix()