Explicitly pass jvmDefaultMode

This commit is contained in:
Mikhael Bogdanov
2020-02-03 15:43:40 +01:00
committed by Mikhail Bogdanov
parent 954ef7d7d6
commit bfd709290b
17 changed files with 81 additions and 62 deletions
@@ -22,9 +22,7 @@ import org.jetbrains.kotlin.codegen.intrinsics.HashCode;
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods; import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods;
import org.jetbrains.kotlin.codegen.state.GenerationState; import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper; import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
import org.jetbrains.kotlin.config.JvmTarget; import org.jetbrains.kotlin.config.*;
import org.jetbrains.kotlin.config.LanguageFeature;
import org.jetbrains.kotlin.config.LanguageVersionSettings;
import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.incremental.components.NoLookupLocation; import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
import org.jetbrains.kotlin.lexer.KtTokens; import org.jetbrains.kotlin.lexer.KtTokens;
@@ -308,9 +306,9 @@ public class AsmUtil {
return new Method(name, Type.getMethodDescriptor(returnType, parameterTypes)); return new Method(name, Type.getMethodDescriptor(returnType, parameterTypes));
} }
public static boolean isAbstractMethod(FunctionDescriptor functionDescriptor, OwnerKind kind) { public static boolean isAbstractMethod(FunctionDescriptor functionDescriptor, OwnerKind kind, JvmDefaultMode jvmDefaultMode) {
return (functionDescriptor.getModality() == Modality.ABSTRACT || return (functionDescriptor.getModality() == Modality.ABSTRACT ||
(isJvmInterface(functionDescriptor.getContainingDeclaration()) && !hasJvmDefaultAnnotation(functionDescriptor))) (isJvmInterface(functionDescriptor.getContainingDeclaration()) && !hasJvmDefaultAnnotation(functionDescriptor, jvmDefaultMode)))
&& !isStaticMethod(kind, functionDescriptor); && !isStaticMethod(kind, functionDescriptor);
} }
@@ -325,10 +323,15 @@ public class AsmUtil {
} }
public static int getMethodAsmFlags(FunctionDescriptor functionDescriptor, OwnerKind kind, GenerationState state) { public static int getMethodAsmFlags(FunctionDescriptor functionDescriptor, OwnerKind kind, GenerationState state) {
return getMethodAsmFlags(functionDescriptor, kind, state.getDeprecationProvider()); return getMethodAsmFlags(functionDescriptor, kind, state.getDeprecationProvider(), state.getJvmDefaultMode());
} }
public static int getMethodAsmFlags(FunctionDescriptor functionDescriptor, OwnerKind kind, DeprecationResolver deprecationResolver) { public static int getMethodAsmFlags(
FunctionDescriptor functionDescriptor,
OwnerKind kind,
DeprecationResolver deprecationResolver,
JvmDefaultMode jvmDefaultMode
) {
int flags = getCommonCallableFlags(functionDescriptor, kind, deprecationResolver); int flags = getCommonCallableFlags(functionDescriptor, kind, deprecationResolver);
for (AnnotationCodegen.JvmFlagAnnotation flagAnnotation : AnnotationCodegen.METHOD_FLAGS) { for (AnnotationCodegen.JvmFlagAnnotation flagAnnotation : AnnotationCodegen.METHOD_FLAGS) {
@@ -356,7 +359,7 @@ public class AsmUtil {
flags |= ACC_STATIC; flags |= ACC_STATIC;
} }
if (isAbstractMethod(functionDescriptor, kind)) { if (isAbstractMethod(functionDescriptor, kind, jvmDefaultMode)) {
flags |= ACC_ABSTRACT; flags |= ACC_ABSTRACT;
} }
@@ -222,7 +222,7 @@ public abstract class ClassBodyCodegen extends MemberCodegen<KtPureClassOrObject
for (Map.Entry<FunctionDescriptor, FunctionDescriptor> entry : CodegenUtil.getNonPrivateTraitMethods(descriptor).entrySet()) { for (Map.Entry<FunctionDescriptor, FunctionDescriptor> entry : CodegenUtil.getNonPrivateTraitMethods(descriptor).entrySet()) {
FunctionDescriptor interfaceFun = entry.getKey(); FunctionDescriptor interfaceFun = entry.getKey();
//skip java 8 default methods //skip java 8 default methods
if (!CodegenUtilKt.isDefinitelyNotDefaultImplsMethod(interfaceFun) && !hasJvmDefaultAnnotation(interfaceFun)) { if (!CodegenUtilKt.isDefinitelyNotDefaultImplsMethod(interfaceFun) && !hasJvmDefaultAnnotation(interfaceFun, state.getJvmDefaultMode())) {
generateDelegationToDefaultImpl(interfaceFun, entry.getValue()); generateDelegationToDefaultImpl(interfaceFun, entry.getValue());
} }
} }
@@ -447,7 +447,7 @@ public class FunctionCodegen {
) { ) {
OwnerKind contextKind = methodContext.getContextKind(); OwnerKind contextKind = methodContext.getContextKind();
if (!state.getClassBuilderMode().generateBodies if (!state.getClassBuilderMode().generateBodies
|| isAbstractMethod(functionDescriptor, contextKind) || isAbstractMethod(functionDescriptor, contextKind, state.getJvmDefaultMode())
|| shouldSkipMethodBodyInAbiMode(state.getClassBuilderMode(), origin) || shouldSkipMethodBodyInAbiMode(state.getClassBuilderMode(), origin)
) { ) {
generateLocalVariableTable( generateLocalVariableTable(
@@ -732,7 +732,7 @@ public class FunctionCodegen {
@NotNull JvmDefaultMode jvmDefaultMode @NotNull JvmDefaultMode jvmDefaultMode
) { ) {
return OwnerKind.DEFAULT_IMPLS == context.getContextKind() && return OwnerKind.DEFAULT_IMPLS == context.getContextKind() &&
hasJvmDefaultAnnotation(functionDescriptor) && hasJvmDefaultAnnotation(functionDescriptor, jvmDefaultMode) &&
jvmDefaultMode.isCompatibility(); jvmDefaultMode.isCompatibility();
} }
@@ -1000,7 +1000,7 @@ public class FunctionCodegen {
public void generateBridges(@NotNull FunctionDescriptor descriptor) { public void generateBridges(@NotNull FunctionDescriptor descriptor) {
if (descriptor instanceof ConstructorDescriptor) return; if (descriptor instanceof ConstructorDescriptor) return;
if (owner.getContextKind() == OwnerKind.DEFAULT_IMPLS) return; if (owner.getContextKind() == OwnerKind.DEFAULT_IMPLS) return;
if (JvmBridgesImplKt.isAbstractOnJvmIgnoringActualModality(descriptor)) return; if (JvmBridgesImplKt.isAbstractOnJvmIgnoringActualModality(descriptor, state.getJvmDefaultMode())) return;
// equals(Any?), hashCode(), toString() never need bridges // equals(Any?), hashCode(), toString() never need bridges
if (isMethodOfAny(descriptor)) return; if (isMethodOfAny(descriptor)) return;
@@ -1036,7 +1036,7 @@ public class FunctionCodegen {
} }
} }
if (!descriptor.getKind().isReal() && isAbstractMethod(descriptor, OwnerKind.IMPLEMENTATION)) { if (!descriptor.getKind().isReal() && isAbstractMethod(descriptor, OwnerKind.IMPLEMENTATION, state.getJvmDefaultMode())) {
CallableDescriptor overridden = SpecialBuiltinMembers.getOverriddenBuiltinReflectingJvmDescriptor(descriptor); CallableDescriptor overridden = SpecialBuiltinMembers.getOverriddenBuiltinReflectingJvmDescriptor(descriptor);
assert overridden != null; assert overridden != null;
@@ -1460,7 +1460,7 @@ public class FunctionCodegen {
iv.invokespecial(parentInternalName, delegateTo.getName(), delegateTo.getDescriptor(), false); iv.invokespecial(parentInternalName, delegateTo.getName(), delegateTo.getDescriptor(), false);
} }
else { else {
if (hasJvmDefaultAnnotation(descriptor)) { if (hasJvmDefaultAnnotation(descriptor, state.getJvmDefaultMode())) {
iv.invokeinterface(v.getThisName(), delegateTo.getName(), delegateTo.getDescriptor()); iv.invokeinterface(v.getThisName(), delegateTo.getName(), delegateTo.getDescriptor());
} }
else { else {
@@ -1650,7 +1650,7 @@ public class FunctionCodegen {
assert isInterface(containingDeclaration) : "'processInterfaceMethod' method should be called only for interfaces, but: " + assert isInterface(containingDeclaration) : "'processInterfaceMethod' method should be called only for interfaces, but: " +
containingDeclaration; containingDeclaration;
if (hasJvmDefaultAnnotation(memberDescriptor)) { if (hasJvmDefaultAnnotation(memberDescriptor, mode)) {
return (kind != OwnerKind.DEFAULT_IMPLS && !isSynthetic) || return (kind != OwnerKind.DEFAULT_IMPLS && !isSynthetic) ||
(kind == OwnerKind.DEFAULT_IMPLS && (isSynthetic || mode.isCompatibility())); (kind == OwnerKind.DEFAULT_IMPLS && (isSynthetic || mode.isCompatibility()));
} else { } else {
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.codegen
import org.jetbrains.kotlin.backend.common.bridges.* import org.jetbrains.kotlin.backend.common.bridges.*
import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.config.JvmDefaultMode
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
@@ -29,17 +30,17 @@ class DescriptorBasedFunctionHandleForJvm(
For non-@JvmDefault interfaces function, its body is generated in a separate place (DefaultImpls) and For non-@JvmDefault interfaces function, its body is generated in a separate place (DefaultImpls) and
the method in the interface is abstract so we must not generate bridges for such cases. the method in the interface is abstract so we must not generate bridges for such cases.
*/ */
override val isAbstract: Boolean = super.isAbstract || isAbstractOnJvmIgnoringActualModality(descriptor) override val isAbstract: Boolean = super.isAbstract || isAbstractOnJvmIgnoringActualModality(descriptor, state.jvmDefaultMode)
override val mayBeUsedAsSuperImplementation: Boolean = override val mayBeUsedAsSuperImplementation: Boolean =
super.mayBeUsedAsSuperImplementation || descriptor.isJvmDefaultOrPlatformDependent() super.mayBeUsedAsSuperImplementation || descriptor.isJvmDefaultOrPlatformDependent(state.jvmDefaultMode)
private val asmMethod by lazy(LazyThreadSafetyMode.NONE) { private val asmMethod by lazy(LazyThreadSafetyMode.NONE) {
state.typeMapper.mapAsmMethod(descriptor) state.typeMapper.mapAsmMethod(descriptor)
} }
override val isDeclaration: Boolean = override val isDeclaration: Boolean =
descriptor.kind.isReal || needToGenerateDelegationToDefaultImpls(descriptor) descriptor.kind.isReal || needToGenerateDelegationToDefaultImpls(descriptor, state.jvmDefaultMode)
override val mightBeIncorrectCode: Boolean override val mightBeIncorrectCode: Boolean
get() = state.classBuilderMode.mightBeIncorrectCode get() = state.classBuilderMode.mightBeIncorrectCode
@@ -65,23 +66,23 @@ private fun FunctionDescriptor.containerEntityForEqualityAndHashCode(): Any =
private val FunctionDescriptor.isJavaForKotlinOverrideProperty: Boolean private val FunctionDescriptor.isJavaForKotlinOverrideProperty: Boolean
get() = this is PropertyAccessorDescriptor && correspondingProperty is JavaForKotlinOverridePropertyDescriptor get() = this is PropertyAccessorDescriptor && correspondingProperty is JavaForKotlinOverridePropertyDescriptor
private fun CallableMemberDescriptor.isJvmDefaultOrPlatformDependent() = private fun CallableMemberDescriptor.isJvmDefaultOrPlatformDependent(jvmDefaultMode: JvmDefaultMode) =
hasJvmDefaultAnnotation() || hasPlatformDependentAnnotation() hasJvmDefaultAnnotation(jvmDefaultMode) || hasPlatformDependentAnnotation()
private fun needToGenerateDelegationToDefaultImpls(descriptor: FunctionDescriptor): Boolean { private fun needToGenerateDelegationToDefaultImpls(descriptor: FunctionDescriptor, jvmDefaultMode: JvmDefaultMode): Boolean {
if (findInterfaceImplementation(descriptor) == null) return false if (findInterfaceImplementation(descriptor) == null) return false
val overriddenFromInterface = findImplementationFromInterface(descriptor) ?: return false val overriddenFromInterface = findImplementationFromInterface(descriptor) ?: return false
return !overriddenFromInterface.isJvmDefaultOrPlatformDependent() return !overriddenFromInterface.isJvmDefaultOrPlatformDependent(jvmDefaultMode)
} }
/** /**
* @return return true for interface method not annotated with @JvmDefault or @PlatformDependent * @return return true for interface method not annotated with @JvmDefault or @PlatformDependent
*/ */
fun isAbstractOnJvmIgnoringActualModality(descriptor: FunctionDescriptor): Boolean { fun isAbstractOnJvmIgnoringActualModality(descriptor: FunctionDescriptor, jvmDefaultMode: JvmDefaultMode): Boolean {
if (!DescriptorUtils.isInterface(descriptor.containingDeclaration)) return false if (!DescriptorUtils.isInterface(descriptor.containingDeclaration)) return false
return !descriptor.isJvmDefaultOrPlatformDependent() return !descriptor.isJvmDefaultOrPlatformDependent(jvmDefaultMode)
} }
fun <Signature> generateBridgesForFunctionDescriptorForJvm( fun <Signature> generateBridgesForFunctionDescriptorForJvm(
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper; import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
import org.jetbrains.kotlin.config.ApiVersion; import org.jetbrains.kotlin.config.ApiVersion;
import org.jetbrains.kotlin.config.JvmAnalysisFlags; import org.jetbrains.kotlin.config.JvmAnalysisFlags;
import org.jetbrains.kotlin.config.JvmDefaultMode;
import org.jetbrains.kotlin.config.LanguageVersionSettings; import org.jetbrains.kotlin.config.LanguageVersionSettings;
import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor; import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor;
@@ -67,7 +68,7 @@ public class JvmCodegenUtil {
private JvmCodegenUtil() { private JvmCodegenUtil() {
} }
public static boolean isNonDefaultInterfaceMember(@NotNull CallableMemberDescriptor descriptor) { public static boolean isNonDefaultInterfaceMember(@NotNull CallableMemberDescriptor descriptor, @NotNull JvmDefaultMode jvmDefaultMode) {
if (!isJvmInterface(descriptor.getContainingDeclaration())) { if (!isJvmInterface(descriptor.getContainingDeclaration())) {
return false; return false;
} }
@@ -75,7 +76,7 @@ public class JvmCodegenUtil {
return descriptor.getModality() == Modality.ABSTRACT; return descriptor.getModality() == Modality.ABSTRACT;
} }
return !hasJvmDefaultAnnotation(descriptor); return !hasJvmDefaultAnnotation(descriptor, jvmDefaultMode);
} }
public static boolean isJvmInterface(@Nullable DeclarationDescriptor descriptor) { public static boolean isJvmInterface(@Nullable DeclarationDescriptor descriptor) {
@@ -402,7 +402,7 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
ClassDescriptor classDescriptor = ((ClassContext) outermost).getContextDescriptor(); ClassDescriptor classDescriptor = ((ClassContext) outermost).getContextDescriptor();
if (context instanceof MethodContext) { if (context instanceof MethodContext) {
FunctionDescriptor functionDescriptor = ((MethodContext) context).getFunctionDescriptor(); FunctionDescriptor functionDescriptor = ((MethodContext) context).getFunctionDescriptor();
if (isInterface(functionDescriptor.getContainingDeclaration()) && !hasJvmDefaultAnnotation(functionDescriptor)) { if (isInterface(functionDescriptor.getContainingDeclaration()) && !hasJvmDefaultAnnotation(functionDescriptor, state.getJvmDefaultMode())) {
return typeMapper.mapDefaultImpls(classDescriptor); return typeMapper.mapDefaultImpls(classDescriptor);
} }
} }
@@ -744,7 +744,7 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
protected final void generateSyntheticAccessors() { protected final void generateSyntheticAccessors() {
for (AccessorForCallableDescriptor<?> accessor : ((CodegenContext<?>) context).getAccessors()) { for (AccessorForCallableDescriptor<?> accessor : ((CodegenContext<?>) context).getAccessors()) {
boolean hasJvmDefaultAnnotation = hasJvmDefaultAnnotation(accessor.getCalleeDescriptor()); boolean hasJvmDefaultAnnotation = hasJvmDefaultAnnotation(accessor.getCalleeDescriptor(), state.getJvmDefaultMode());
OwnerKind kind = context.getContextKind(); OwnerKind kind = context.getContextKind();
if (!isInterface(context.getContextDescriptor()) || if (!isInterface(context.getContextDescriptor()) ||
@@ -934,7 +934,7 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
boolean isJvmStaticInObjectOrClass = CodegenUtilKt.isJvmStaticInObjectOrClassOrInterface(functionDescriptor); boolean isJvmStaticInObjectOrClass = CodegenUtilKt.isJvmStaticInObjectOrClassOrInterface(functionDescriptor);
boolean hasDispatchReceiver = !isStaticDeclaration(functionDescriptor) && boolean hasDispatchReceiver = !isStaticDeclaration(functionDescriptor) &&
!isNonDefaultInterfaceMember(functionDescriptor) && !isNonDefaultInterfaceMember(functionDescriptor, state.getJvmDefaultMode()) &&
!isJvmStaticInObjectOrClass && !isJvmStaticInObjectOrClass &&
!InlineClassesUtilsKt.isInlineClass(functionDescriptor.getContainingDeclaration()); !InlineClassesUtilsKt.isInlineClass(functionDescriptor.getContainingDeclaration());
boolean accessorIsConstructor = accessorDescriptor instanceof AccessorForConstructorDescriptor; boolean accessorIsConstructor = accessorDescriptor instanceof AccessorForConstructorDescriptor;
@@ -438,7 +438,7 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
@NotNull D descriptor, @NotNull D descriptor,
@Nullable ClassDescriptor superCallTarget, @Nullable ClassDescriptor superCallTarget,
@NotNull GenerationState state) { @NotNull GenerationState state) {
if (superCallTarget != null && !isNonDefaultInterfaceMember(descriptor)) { if (superCallTarget != null && !isNonDefaultInterfaceMember(descriptor, state.getJvmDefaultMode())) {
CodegenContext afterInline = getFirstCrossInlineOrNonInlineContext(); CodegenContext afterInline = getFirstCrossInlineOrNonInlineContext();
CodegenContext c = afterInline.findParentContextWithDescriptor(superCallTarget); CodegenContext c = afterInline.findParentContextWithDescriptor(superCallTarget);
assert c != null : "Couldn't find a context for a super-call: " + descriptor; assert c != null : "Couldn't find a context for a super-call: " + descriptor;
@@ -593,8 +593,8 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
CodegenContext properContext = getFirstCrossInlineOrNonInlineContext(); CodegenContext properContext = getFirstCrossInlineOrNonInlineContext();
DeclarationDescriptor enclosing = descriptor.getContainingDeclaration(); DeclarationDescriptor enclosing = descriptor.getContainingDeclaration();
boolean isInliningContext = properContext.isInlineMethodContext(); boolean isInliningContext = properContext.isInlineMethodContext();
boolean sameJvmDefault = hasJvmDefaultAnnotation(descriptor) == boolean sameJvmDefault = hasJvmDefaultAnnotation(descriptor, getState().getJvmDefaultMode()) ==
isCallableMemberWithJvmDefaultAnnotation(properContext.contextDescriptor) || isCallableMemberWithJvmDefaultAnnotation(properContext.contextDescriptor, getState().getJvmDefaultMode()) ||
properContext.contextDescriptor instanceof AccessorForCallableDescriptor; properContext.contextDescriptor instanceof AccessorForCallableDescriptor;
if (!isInliningContext && ( if (!isInliningContext && (
!properContext.hasThisDescriptor() || !properContext.hasThisDescriptor() ||
@@ -651,7 +651,7 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
return descriptor; return descriptor;
} }
if (hasJvmDefaultAnnotation(descriptor) && descriptorContext instanceof DefaultImplsClassContext) { if (hasJvmDefaultAnnotation(descriptor, getState().getJvmDefaultMode()) && descriptorContext instanceof DefaultImplsClassContext) {
descriptorContext = ((DefaultImplsClassContext) descriptorContext).getInterfaceContext(); descriptorContext = ((DefaultImplsClassContext) descriptorContext).getInterfaceContext();
} }
@@ -408,7 +408,7 @@ class PsiSourceCompilerForInline(private val codegen: ExpressionCodegen, overrid
when { when {
DescriptorUtils.isInterface(descriptor) && DescriptorUtils.isInterface(descriptor) &&
innerDescriptor !is ClassDescriptor && innerDescriptor !is ClassDescriptor &&
!innerDescriptor.isCallableMemberWithJvmDefaultAnnotation() -> !innerDescriptor.isCallableMemberWithJvmDefaultAnnotation(state.jvmDefaultMode) ->
OwnerKind.DEFAULT_IMPLS OwnerKind.DEFAULT_IMPLS
else -> else ->
OwnerKind.IMPLEMENTATION OwnerKind.IMPLEMENTATION
@@ -54,6 +54,7 @@ class JvmSerializerExtension @JvmOverloads constructor(
private val isParamAssertionsDisabled = state.isParamAssertionsDisabled private val isParamAssertionsDisabled = state.isParamAssertionsDisabled
private val unifiedNullChecks = state.unifiedNullChecks private val unifiedNullChecks = state.unifiedNullChecks
override val metadataVersion = state.metadataVersion override val metadataVersion = state.metadataVersion
private val jvmDefaultMode = state.jvmDefaultMode
override fun shouldUseTypeTable(): Boolean = useTypeTable override fun shouldUseTypeTable(): Boolean = useTypeTable
override fun shouldSerializeFunction(descriptor: FunctionDescriptor): Boolean { override fun shouldSerializeFunction(descriptor: FunctionDescriptor): Boolean {
@@ -98,7 +99,7 @@ class JvmSerializerExtension @JvmOverloads constructor(
if ( if (
isInterface(classDescriptor) && isInterface(classDescriptor) &&
classDescriptor.unsubstitutedMemberScope.getContributedDescriptors().any { classDescriptor.unsubstitutedMemberScope.getContributedDescriptors().any {
it is CallableMemberDescriptor && it.hasJvmDefaultAnnotation() it is CallableMemberDescriptor && it.hasJvmDefaultAnnotation(jvmDefaultMode) //TODO: new requirements for new option
} }
) { ) {
builder.addVersionRequirement( builder.addVersionRequirement(
@@ -21,10 +21,7 @@ import org.jetbrains.kotlin.codegen.inline.FictitiousArrayConstructor
import org.jetbrains.kotlin.codegen.signature.AsmTypeFactory import org.jetbrains.kotlin.codegen.signature.AsmTypeFactory
import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter
import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter
import org.jetbrains.kotlin.config.JvmTarget import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.* import org.jetbrains.kotlin.descriptors.impl.*
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil
@@ -89,6 +86,7 @@ class KotlinTypeMapper @JvmOverloads constructor(
private val namePreprocessor: ((ClassDescriptor) -> String?)? = null private val namePreprocessor: ((ClassDescriptor) -> String?)? = null
) : KotlinTypeMapperBase() { ) : KotlinTypeMapperBase() {
private val isReleaseCoroutines = languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines) private val isReleaseCoroutines = languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines)
val jvmDefaultMode = languageVersionSettings.getFlag(JvmAnalysisFlags.jvmDefaultMode)
private val typeMappingConfiguration = object : TypeMappingConfiguration<Type> { private val typeMappingConfiguration = object : TypeMappingConfiguration<Type> {
override fun commonSupertype(types: Collection<KotlinType>): KotlinType { override fun commonSupertype(types: Collection<KotlinType>): KotlinType {
@@ -424,7 +422,7 @@ class KotlinTypeMapper @JvmOverloads constructor(
val functionParent = descriptor.original.containingDeclaration val functionParent = descriptor.original.containingDeclaration
var functionDescriptor = findSuperDeclaration(descriptor.original, superCall) var functionDescriptor = findSuperDeclaration(descriptor.original, superCall, jvmDefaultMode)
val signature: JvmMethodSignature val signature: JvmMethodSignature
val returnKotlinType: KotlinType? val returnKotlinType: KotlinType?
@@ -449,8 +447,8 @@ class KotlinTypeMapper @JvmOverloads constructor(
baseMethodDescriptor = findBaseDeclaration(functionDescriptor).original baseMethodDescriptor = findBaseDeclaration(functionDescriptor).original
val ownerForDefault = baseMethodDescriptor.containingDeclaration as ClassDescriptor val ownerForDefault = baseMethodDescriptor.containingDeclaration as ClassDescriptor
isDefaultMethodInInterface = isJvmInterface(ownerForDefault) && baseMethodDescriptor.hasJvmDefaultAnnotation() isDefaultMethodInInterface = isJvmInterface(ownerForDefault) && baseMethodDescriptor.hasJvmDefaultAnnotation(jvmDefaultMode)
ownerForDefaultImpl = if (isJvmInterface(ownerForDefault) && !baseMethodDescriptor.hasJvmDefaultAnnotation()) ownerForDefaultImpl = if (isJvmInterface(ownerForDefault) && !baseMethodDescriptor.hasJvmDefaultAnnotation(jvmDefaultMode))
mapDefaultImpls(ownerForDefault) mapDefaultImpls(ownerForDefault)
else else
mapClass(ownerForDefault) mapClass(ownerForDefault)
@@ -458,7 +456,7 @@ class KotlinTypeMapper @JvmOverloads constructor(
if (isInterface && (superCall || descriptor.visibility == Visibilities.PRIVATE || isAccessor(descriptor))) { if (isInterface && (superCall || descriptor.visibility == Visibilities.PRIVATE || isAccessor(descriptor))) {
thisClass = mapClass(functionParent) thisClass = mapClass(functionParent)
dispatchReceiverKotlinType = functionParent.defaultType dispatchReceiverKotlinType = functionParent.defaultType
if (declarationOwner is JavaClassDescriptor || declarationFunctionDescriptor.hasJvmDefaultAnnotation()) { if (declarationOwner is JavaClassDescriptor || declarationFunctionDescriptor.hasJvmDefaultAnnotation(jvmDefaultMode)) {
invokeOpcode = INVOKESPECIAL invokeOpcode = INVOKESPECIAL
signature = mapSignatureSkipGeneric(functionDescriptor) signature = mapSignatureSkipGeneric(functionDescriptor)
returnKotlinType = functionDescriptor.returnType returnKotlinType = functionDescriptor.returnType
@@ -469,7 +467,7 @@ class KotlinTypeMapper @JvmOverloads constructor(
val originalDescriptor = descriptor.original val originalDescriptor = descriptor.original
signature = mapSignatureSkipGeneric(originalDescriptor, OwnerKind.DEFAULT_IMPLS) signature = mapSignatureSkipGeneric(originalDescriptor, OwnerKind.DEFAULT_IMPLS)
returnKotlinType = getReturnValueType(originalDescriptor) returnKotlinType = getReturnValueType(originalDescriptor)
if (descriptor is AccessorForCallableDescriptor<*> && descriptor.calleeDescriptor.hasJvmDefaultAnnotation()) { if (descriptor is AccessorForCallableDescriptor<*> && descriptor.calleeDescriptor.hasJvmDefaultAnnotation(jvmDefaultMode)) {
owner = mapClass(functionParent) owner = mapClass(functionParent)
isInterfaceMember = true isInterfaceMember = true
} else { } else {
@@ -1510,7 +1508,7 @@ class KotlinTypeMapper @JvmOverloads constructor(
} }
//NB: similar platform agnostic code in DescriptorUtils.unwrapFakeOverride //NB: similar platform agnostic code in DescriptorUtils.unwrapFakeOverride
private fun findSuperDeclaration(descriptor: FunctionDescriptor, isSuperCall: Boolean): FunctionDescriptor { private fun findSuperDeclaration(descriptor: FunctionDescriptor, isSuperCall: Boolean, jvmDefaultMode: JvmDefaultMode): FunctionDescriptor {
var current = descriptor var current = descriptor
while (current.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) { while (current.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
val classCallable = current.overriddenDescriptors.firstOrNull { !isInterface(it.containingDeclaration) } val classCallable = current.overriddenDescriptors.firstOrNull { !isInterface(it.containingDeclaration) }
@@ -1519,7 +1517,7 @@ class KotlinTypeMapper @JvmOverloads constructor(
current = classCallable current = classCallable
continue continue
} }
if (isSuperCall && !current.hasJvmDefaultAnnotation() && !isInterface(current.containingDeclaration)) { if (isSuperCall && !current.hasJvmDefaultAnnotation(jvmDefaultMode) && !isInterface(current.containingDeclaration)) {
//Don't unwrap fake overrides from class to interface cause substituted override would be implicitly generated //Don't unwrap fake overrides from class to interface cause substituted override would be implicitly generated
return current return current
} }
@@ -8,13 +8,18 @@ package org.jetbrains.kotlin.config
enum class JvmDefaultMode(val description: String) { enum class JvmDefaultMode(val description: String) {
DISABLE("disable"), DISABLE("disable"),
ENABLE("enable"), ENABLE("enable"),
ENABLE_WITH_DEFAULT_IMPLS("compatibility"); ENABLE_WITH_DEFAULT_IMPLS("compatibility"),
ALL_COMPATIBILITY("all-compatibility"),
ALL_INCOMPATIBLE("all");
val isEnabled val isEnabled
get() = this != DISABLE get() = this != DISABLE
val isCompatibility val isCompatibility
get() = this == ENABLE_WITH_DEFAULT_IMPLS get() = this == ENABLE_WITH_DEFAULT_IMPLS || this == ALL_COMPATIBILITY
val forAllMehtodsWithBody
get() = this == ALL_COMPATIBILITY || this == ALL_INCOMPATIBLE
companion object { companion object {
@JvmField @JvmField
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.resolve.jvm package org.jetbrains.kotlin.resolve.jvm
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.config.JvmAnalysisFlags
import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
@@ -35,7 +36,7 @@ object JvmDelegationFilter : DelegationFilter {
//We always have only one implementation otherwise it's an error in kotlin and java //We always have only one implementation otherwise it's an error in kotlin and java
val realMember = DescriptorUtils.unwrapFakeOverride(interfaceMember) val realMember = DescriptorUtils.unwrapFakeOverride(interfaceMember)
return !isJavaDefaultMethod(realMember) && return !isJavaDefaultMethod(realMember) &&
!realMember.hasJvmDefaultAnnotation() && !realMember.hasJvmDefaultAnnotation(languageVersionSettings.getFlag(JvmAnalysisFlags.jvmDefaultMode)) &&
!isBuiltInMemberMappedToJavaDefault(realMember) !isBuiltInMemberMappedToJavaDefault(realMember)
} }
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.resolve.jvm.annotations package org.jetbrains.kotlin.resolve.jvm.annotations
import org.jetbrains.kotlin.config.JvmDefaultMode
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor
@@ -40,11 +41,11 @@ fun DeclarationDescriptor.findJvmFieldAnnotation(): AnnotationDescriptor? =
fun DeclarationDescriptor.hasJvmFieldAnnotation(): Boolean = fun DeclarationDescriptor.hasJvmFieldAnnotation(): Boolean =
findJvmFieldAnnotation() != null findJvmFieldAnnotation() != null
fun DeclarationDescriptor.isCallableMemberWithJvmDefaultAnnotation(): Boolean = fun DeclarationDescriptor.isCallableMemberWithJvmDefaultAnnotation(jvmDefault: JvmDefaultMode): Boolean =
this is CallableMemberDescriptor && hasJvmDefaultAnnotation() this is CallableMemberDescriptor && hasJvmDefaultAnnotation(jvmDefault)
fun CallableMemberDescriptor.hasJvmDefaultAnnotation(): Boolean = fun CallableMemberDescriptor.hasJvmDefaultAnnotation(jvmDefault: JvmDefaultMode): Boolean =
DescriptorUtils.getDirectMember(this).annotations.hasAnnotation(JVM_DEFAULT_FQ_NAME) jvmDefault.forAllMehtodsWithBody || DescriptorUtils.getDirectMember(this).annotations.hasAnnotation(JVM_DEFAULT_FQ_NAME)
fun CallableMemberDescriptor.hasPlatformDependentAnnotation(): Boolean = fun CallableMemberDescriptor.hasPlatformDependentAnnotation(): Boolean =
DescriptorUtils.getDirectMember(this).annotations.hasAnnotation(PLATFORM_DEPENDENT_ANNOTATION_FQ_NAME) DescriptorUtils.getDirectMember(this).annotations.hasAnnotation(PLATFORM_DEPENDENT_ANNOTATION_FQ_NAME)
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.resolve.jvm.checkers package org.jetbrains.kotlin.resolve.jvm.checkers
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.config.JvmAnalysisFlags
import org.jetbrains.kotlin.config.JvmTarget import org.jetbrains.kotlin.config.JvmTarget
import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
@@ -61,13 +62,14 @@ class InterfaceDefaultMethodCallChecker(val jvmTarget: JvmTarget) : CallChecker
val realDescriptor = unwrapFakeOverride(descriptor) val realDescriptor = unwrapFakeOverride(descriptor)
val realDescriptorOwner = realDescriptor.containingDeclaration as? ClassDescriptor ?: return val realDescriptorOwner = realDescriptor.containingDeclaration as? ClassDescriptor ?: return
if (isInterface(realDescriptorOwner) && (realDescriptor is JavaCallableMemberDescriptor || realDescriptor.hasJvmDefaultAnnotation())) { val jvmDefaultMode = context.languageVersionSettings.getFlag(JvmAnalysisFlags.jvmDefaultMode)
if (isInterface(realDescriptorOwner) && (realDescriptor is JavaCallableMemberDescriptor || realDescriptor.hasJvmDefaultAnnotation(jvmDefaultMode))) {
val bindingContext = context.trace.bindingContext val bindingContext = context.trace.bindingContext
val thisForSuperCall = getSuperCallLabelTarget(bindingContext, superCallExpression) val thisForSuperCall = getSuperCallLabelTarget(bindingContext, superCallExpression)
if (thisForSuperCall != null && DescriptorUtils.isInterface(thisForSuperCall)) { if (thisForSuperCall != null && DescriptorUtils.isInterface(thisForSuperCall)) {
val declarationWithCall = findInterfaceMember(thisForSuperCall, superCallExpression, bindingContext) val declarationWithCall = findInterfaceMember(thisForSuperCall, superCallExpression, bindingContext)
if (declarationWithCall?.hasJvmDefaultAnnotation() == false) { if (declarationWithCall?.hasJvmDefaultAnnotation(jvmDefaultMode) == false) {
context.trace.report(INTERFACE_CANT_CALL_DEFAULT_METHOD_VIA_SUPER.on(reportOn)) context.trace.report(INTERFACE_CANT_CALL_DEFAULT_METHOD_VIA_SUPER.on(reportOn))
return return
} }
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.resolve.jvm.checkers package org.jetbrains.kotlin.resolve.jvm.checkers
import org.jetbrains.kotlin.config.JvmAnalysisFlags import org.jetbrains.kotlin.config.JvmAnalysisFlags
import org.jetbrains.kotlin.config.JvmDefaultMode
import org.jetbrains.kotlin.config.JvmTarget import org.jetbrains.kotlin.config.JvmTarget
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor
@@ -40,9 +41,9 @@ class JvmDefaultChecker(val jvmTarget: JvmTarget) : DeclarationChecker {
if (descriptor is ClassDescriptor) { if (descriptor is ClassDescriptor) {
val hasDeclaredJvmDefaults = val hasDeclaredJvmDefaults =
descriptor.unsubstitutedMemberScope.getContributedDescriptors().filterIsInstance<CallableMemberDescriptor>().any { descriptor.unsubstitutedMemberScope.getContributedDescriptors().filterIsInstance<CallableMemberDescriptor>().any {
it.kind.isReal && it.hasJvmDefaultAnnotation() it.kind.isReal && it.hasJvmDefaultAnnotation(jvmDefaultMode)
} }
if (!hasDeclaredJvmDefaults && !checkJvmDefaultsInHierarchy(descriptor, jvmDefaultMode.isEnabled)) { if (!hasDeclaredJvmDefaults && !checkJvmDefaultsInHierarchy(descriptor, jvmDefaultMode)) {
context.trace.report(ErrorsJvm.JVM_DEFAULT_THROUGH_INHERITANCE.on(declaration)) context.trace.report(ErrorsJvm.JVM_DEFAULT_THROUGH_INHERITANCE.on(declaration))
} }
} }
@@ -65,15 +66,15 @@ class JvmDefaultChecker(val jvmTarget: JvmTarget) : DeclarationChecker {
} }
} }
private fun checkJvmDefaultsInHierarchy(descriptor: DeclarationDescriptor, enableJvmDefault: Boolean): Boolean { private fun checkJvmDefaultsInHierarchy(descriptor: DeclarationDescriptor, jvmDefaultMode: JvmDefaultMode): Boolean {
if (enableJvmDefault) return true if (jvmDefaultMode.isEnabled) return true
if (descriptor !is ClassDescriptor) return true if (descriptor !is ClassDescriptor) return true
return descriptor.unsubstitutedMemberScope.getContributedDescriptors().filterIsInstance<CallableMemberDescriptor>() return descriptor.unsubstitutedMemberScope.getContributedDescriptors().filterIsInstance<CallableMemberDescriptor>()
.all { memberDescriptor -> .all { memberDescriptor ->
memberDescriptor.kind.isReal || OverridingUtil.filterOutOverridden(memberDescriptor.overriddenDescriptors.toSet()).all { memberDescriptor.kind.isReal || OverridingUtil.filterOutOverridden(memberDescriptor.overriddenDescriptors.toSet()).all {
!isInterface(it.containingDeclaration) || !it.hasJvmDefaultAnnotation() || it.modality == Modality.ABSTRACT !isInterface(it.containingDeclaration) || !it.hasJvmDefaultAnnotation(jvmDefaultMode) || it.modality == Modality.ABSTRACT
} }
} }
} }
@@ -23,7 +23,7 @@ class JvmDefaultSuperCallChecker : CallChecker {
if (getSuperCallExpression(resolvedCall.call) == null) return if (getSuperCallExpression(resolvedCall.call) == null) return
val resultingDescriptor = resolvedCall.resultingDescriptor as? CallableMemberDescriptor ?: return val resultingDescriptor = resolvedCall.resultingDescriptor as? CallableMemberDescriptor ?: return
if (!resultingDescriptor.hasJvmDefaultAnnotation()) return if (!resultingDescriptor.hasJvmDefaultAnnotation(jvmDefaultMode)) return
if (DescriptorUtils.isInterface(resultingDescriptor.containingDeclaration)) { if (DescriptorUtils.isInterface(resultingDescriptor.containingDeclaration)) {
context.trace.report(ErrorsJvm.USAGE_OF_JVM_DEFAULT_THROUGH_SUPER_CALL.on(reportOn)) context.trace.report(ErrorsJvm.USAGE_OF_JVM_DEFAULT_THROUGH_SUPER_CALL.on(reportOn))
@@ -248,7 +248,12 @@ private fun KtUltraLightClass.lightMethod(
val name = if (descriptor is ConstructorDescriptor) name else support.typeMapper.mapFunctionName(descriptor, OwnerKind.IMPLEMENTATION) val name = if (descriptor is ConstructorDescriptor) name else support.typeMapper.mapFunctionName(descriptor, OwnerKind.IMPLEMENTATION)
val accessFlags: Int by lazyPub { val accessFlags: Int by lazyPub {
val asmFlags = AsmUtil.getMethodAsmFlags(descriptor, OwnerKind.IMPLEMENTATION, support.deprecationResolver) val asmFlags = AsmUtil.getMethodAsmFlags(
descriptor,
OwnerKind.IMPLEMENTATION,
support.deprecationResolver,
support.typeMapper.jvmDefaultMode,
)
packMethodFlags(asmFlags, JvmCodegenUtil.isJvmInterface(kotlinOrigin.resolve() as? ClassDescriptor)) packMethodFlags(asmFlags, JvmCodegenUtil.isJvmInterface(kotlinOrigin.resolve() as? ClassDescriptor))
} }