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 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 (directMember.annotations.hasAnnotation(JVM_DEFAULT_FQ_NAME)) return true
if (clazz !is DeserializedClassDescriptor) return jvmDefault.forAllMethodsWithBody if (clazz !is DeserializedClassDescriptor) return jvmDefault.forAllMethodsWithBody
return JvmProtoBufUtil.isNewPlaceForBodyGeneration(clazz.classProto) return JvmProtoBufUtil.isNewPlaceForBodyGeneration(clazz.classProto)
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.backend.jvm.ir 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.common.lower.IrLoweringContext
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
@@ -147,10 +148,17 @@ fun IrDeclaration.getJvmNameFromAnnotation(): String? {
val IrFunction.propertyIfAccessor: IrDeclaration val IrFunction.propertyIfAccessor: IrDeclaration
get() = (this as? IrSimpleFunction)?.correspondingPropertySymbol?.owner ?: this 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 if (hasJvmDefault()) return true
val parentDescriptor = propertyIfAccessor.parentAsClass.descriptor val parentDescriptor = propertyIfAccessor.parentAsClass.descriptor
if (parentDescriptor !is DeserializedClassDescriptor) return jvmDefaultMode.forAllMehtodsWithBody if (parentDescriptor !is DeserializedClassDescriptor) return jvmDefaultMode.forAllMethodsWithBody
return JvmProtoBufUtil.isNewPlaceForBodyGeneration(parentDescriptor.classProto) return JvmProtoBufUtil.isNewPlaceForBodyGeneration(parentDescriptor.classProto)
} }
@@ -286,10 +294,13 @@ fun IrFunctionAccessExpression.copyFromWithPlaceholderTypeArguments(existingCall
// Check whether a function maps to an abstract method. // 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 // 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 // are abstract unless they are annotated @PlatformDependent or compiled to JVM default (with @JvmDefault annotation or without)
// such an annotation. // or they override such method.
fun IrSimpleFunction.isJvmAbstract(jvmDefaultMode: JvmDefaultMode): Boolean = (modality == Modality.ABSTRACT) || fun IrSimpleFunction.isJvmAbstract(jvmDefaultMode: JvmDefaultMode): Boolean {
(parentAsClass.isJvmInterface && resolveFakeOverride()?.run { !isCompiledToJvmDefault(jvmDefaultMode) && !hasPlatformDependent() } ?: true) if (modality == Modality.ABSTRACT) return true
if (!parentAsClass.isJvmInterface) return false
return resolveFakeOverride()?.run { !isCompiledToJvmDefault(jvmDefaultMode) && !hasPlatformDependent() } != false
}
fun firstSuperMethodFromKotlin( fun firstSuperMethodFromKotlin(
override: IrSimpleFunction, override: IrSimpleFunction,
@@ -153,7 +153,7 @@ private class InterfaceDefaultCallsLowering(val context: JvmBackendContext) : Ir
if (!callee.hasInterfaceParent() || if (!callee.hasInterfaceParent() ||
callee.origin != IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER || callee.origin != IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER ||
callee.isCompiledToJvmDefault(context.state.jvmDefaultMode) callee.isSimpleFunctionCompiledToJvmDefault(context.state.jvmDefaultMode)
) { ) {
return super.visitCall(expression) return super.visitCall(expression)
} }
@@ -171,14 +171,19 @@ private class InterfaceDefaultCallsLowering(val context: JvmBackendContext) : Ir
} }
} }
private fun IrSimpleFunction.isDefinitelyNotDefaultImplsMethod(jvmDefaultMode: JvmDefaultMode) = private fun IrSimpleFunction.isDefinitelyNotDefaultImplsMethod(jvmDefaultMode: JvmDefaultMode): Boolean {
resolveFakeOverride()?.origin == IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB || if (resolveFakeOverride()?.run {
origin == IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER || 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) || hasAnnotation(PLATFORM_DEPENDENT_ANNOTATION_FQ_NAME) ||
isCompiledToJvmDefault(jvmDefaultMode) ||
(name.asString() == "clone" && (name.asString() == "clone" &&
parent.safeAs<IrClass>()?.fqNameWhenAvailable?.asString() == "kotlin.Cloneable" && parent.safeAs<IrClass>()?.fqNameWhenAvailable?.asString() == "kotlin.Cloneable" &&
valueParameters.isEmpty()) valueParameters.isEmpty())
}
internal val interfaceObjectCallsPhase = makeIrFilePhase( internal val interfaceObjectCallsPhase = makeIrFilePhase(
lowering = ::InterfaceObjectCallsLowering, 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.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrLocalDelegatedPropertySymbol 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.types.defaultType
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid 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, * - the implementation is private, or belongs to java.lang.Object,
* or is a stub for function with default parameters ($default) * 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 * - 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, * - we're in -Xjvm-default=enable|all mode, and we have that default implementation,
* in which case we simply leave it. * 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 jvmName = context.methodSignatureMapper.mapFunctionName(this)
val suffix = when { val suffix = when {
// Accessors for top level functions never need a suffix. // 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 only function accessors placed on interfaces are for private functions and JvmDefault implementations.
// The two cannot clash. // 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 // Accessor for _s_uper-qualified call
superQualifier != null -> "\$s" + superQualifier.descriptor.syntheticAccessorToSuperSuffix() superQualifier != null -> "\$s" + superQualifier.descriptor.syntheticAccessorToSuperSuffix()