From 61ec143b748b5fa2194c34a91b7a3bd5ac0ee43f Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Thu, 5 Oct 2023 12:04:37 +0300 Subject: [PATCH] [FIR] Don't generate delegated members for java methods with default implementation ^KT-62334 Fixed --- .../fir/session/ComponentsContainers.kt | 2 + .../fir/session/FirSessionFactoryHelper.kt | 2 + .../jvm/FirJvmDelegatedMembersFilter.kt | 47 +++++++++++++++++++ .../scopes/impl/FirDelegatedMemberScope.kt | 22 +++++++++ .../box/collections/specialBridgeForGet.kt | 2 - .../box/delegation/byMiddleInterface.kt | 2 - .../codegen/box/delegation/delegationToMap.kt | 9 ---- .../codegen/box/delegation/diamond.kt | 2 - .../box/delegation/inClassDeclaration.kt | 2 - .../testData/codegen/box/delegation/mixed.kt | 2 - .../testData/codegen/box/delegation/simple.kt | 2 - ...yImplFromOneJavaInterfaceWithDelegation.kt | 2 - ...ImplFromOneJavaInterfaceWithDelegation2.kt | 2 - .../delegationBy/javaDefaultMethod.kt | 4 +- .../codegen/box/traits/defaultMethod.kt | 2 - .../ir/irText/firProblems/kt43342.fir.ir.txt | 4 ++ 16 files changed, 78 insertions(+), 30 deletions(-) create mode 100644 compiler/fir/java/src/org/jetbrains/kotlin/fir/scopes/jvm/FirJvmDelegatedMembersFilter.kt diff --git a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/ComponentsContainers.kt b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/ComponentsContainers.kt index 6be546dd2de..a8dc304ef54 100644 --- a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/ComponentsContainers.kt +++ b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/ComponentsContainers.kt @@ -54,6 +54,7 @@ import org.jetbrains.kotlin.fir.scopes.FirOverrideService import org.jetbrains.kotlin.fir.scopes.FirPlatformClassMapper import org.jetbrains.kotlin.fir.scopes.PlatformSpecificOverridabilityRules import org.jetbrains.kotlin.fir.scopes.impl.* +import org.jetbrains.kotlin.fir.scopes.jvm.FirJvmDelegatedMembersFilter import org.jetbrains.kotlin.fir.scopes.jvm.JvmMappedScope.FirMappedSymbolStorage import org.jetbrains.kotlin.fir.serialization.FirProvidedDeclarationsForMetadataService import org.jetbrains.kotlin.fir.symbols.FirLazyDeclarationResolver @@ -159,6 +160,7 @@ fun FirSession.registerJavaComponents( register(FirOverridesBackwardCompatibilityHelper::class, FirJvmOverridesBackwardCompatibilityHelper) register(FirInlineCheckerPlatformSpecificComponent::class, FirJvmInlineCheckerComponent()) register(FirGenericArrayClassLiteralSupport::class, FirGenericArrayClassLiteralSupport.Enabled) + register(FirDelegatedMembersFilter::class, FirJvmDelegatedMembersFilter(this)) } // -------------------------- Resolve components -------------------------- diff --git a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/FirSessionFactoryHelper.kt b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/FirSessionFactoryHelper.kt index 7205d7039fc..325215edf15 100644 --- a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/FirSessionFactoryHelper.kt +++ b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/FirSessionFactoryHelper.kt @@ -15,6 +15,7 @@ import org.jetbrains.kotlin.fir.extensions.FirExtensionService import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider import org.jetbrains.kotlin.fir.resolve.calls.ConeCallConflictResolverFactory import org.jetbrains.kotlin.fir.scopes.FirPlatformClassMapper +import org.jetbrains.kotlin.fir.scopes.impl.FirDelegatedMembersFilter import org.jetbrains.kotlin.fir.session.environment.AbstractProjectEnvironment import org.jetbrains.kotlin.fir.session.environment.AbstractProjectFileSearchScope import org.jetbrains.kotlin.incremental.components.EnumWhenTracker @@ -138,5 +139,6 @@ object FirSessionFactoryHelper { register(ConeCallConflictResolverFactory::class, DefaultCallConflictResolverFactory) register(FirPlatformClassMapper::class, FirPlatformClassMapper.Default) register(FirOverridesBackwardCompatibilityHelper::class, FirDefaultOverridesBackwardCompatibilityHelper) + register(FirDelegatedMembersFilter::class, FirDelegatedMembersFilter.Default) } } diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/scopes/jvm/FirJvmDelegatedMembersFilter.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/scopes/jvm/FirJvmDelegatedMembersFilter.kt new file mode 100644 index 00000000000..42469c4e4bb --- /dev/null +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/scopes/jvm/FirJvmDelegatedMembersFilter.kt @@ -0,0 +1,47 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.fir.scopes.jvm + +import org.jetbrains.kotlin.descriptors.Modality +import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin +import org.jetbrains.kotlin.fir.declarations.hasAnnotation +import org.jetbrains.kotlin.fir.declarations.utils.modality +import org.jetbrains.kotlin.fir.scopes.impl.FirDelegatedMembersFilter +import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol +import org.jetbrains.kotlin.fir.unwrapFakeOverrides +import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.JvmStandardClassIds + +/* + * KT-18324: If original is java method with default then delegated function should not be generated + * See org.jetbrains.kotlin.resolve.jvm.JvmDelegationFilter for K1 implementation + */ +class FirJvmDelegatedMembersFilter(private val session: FirSession) : FirDelegatedMembersFilter() { + companion object { + private val PLATFORM_DEPENDENT_ANNOTATION_CLASS_ID = ClassId.topLevel(FqName("kotlin.internal.PlatformDependent")) + } + + override fun shouldNotGenerateDelegatedMember(memberSymbolFromSuperInterface: FirCallableSymbol<*>): Boolean { + val original = memberSymbolFromSuperInterface.unwrapFakeOverrides() + return original.isNonAbstractJavaMethod() || original.hasJvmDefaultAnnotation() || original.isBuiltInMemberMappedToJavaDefault() + } + + // If java interface method is not abstract, then it's a default method. + private fun FirCallableSymbol<*>.isNonAbstractJavaMethod(): Boolean { + return origin == FirDeclarationOrigin.Enhancement && modality != Modality.ABSTRACT + } + + private fun FirCallableSymbol<*>.hasJvmDefaultAnnotation(): Boolean { + return annotations.hasAnnotation(JvmStandardClassIds.JVM_DEFAULT_CLASS_ID, session) + } + + private fun FirCallableSymbol<*>.isBuiltInMemberMappedToJavaDefault(): Boolean { + return modality != Modality.ABSTRACT && + annotations.hasAnnotation(PLATFORM_DEPENDENT_ANNOTATION_CLASS_ID, session) + } +} diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirDelegatedMemberScope.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirDelegatedMemberScope.kt index d819a82712c..61e047da54b 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirDelegatedMemberScope.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirDelegatedMemberScope.kt @@ -9,6 +9,7 @@ import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.fir.DelegatedWrapperData import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.FirSessionComponent import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.utils.classId import org.jetbrains.kotlin.fir.declarations.utils.modality @@ -39,6 +40,7 @@ class FirDelegatedMemberScope( ) : FirContainingNamesAwareScope() { private val dispatchReceiverType = containingClass.defaultType() private val overrideChecker = session.firOverrideChecker + private val delegatedMembersFilter = session.delegatedMembersFilter override fun processFunctionsByName(name: Name, processor: (FirNamedFunctionSymbol) -> Unit) { declaredMemberScope.processFunctionsByName(name, processor) @@ -80,6 +82,10 @@ class FirDelegatedMemberScope( return@processor } + if (delegatedMembersFilter.shouldNotGenerateDelegatedMember(original.symbol)) { + return@processor + } + if (declaredMemberScope.getFunctions(name).any { overrideChecker.isOverriddenFunction(it.fir, original) }) { return@processor } @@ -143,6 +149,10 @@ class FirDelegatedMemberScope( return@processor } + if (delegatedMembersFilter.shouldNotGenerateDelegatedMember(propertySymbol)) { + return@processor + } + val original = propertySymbol.fir var isOverriddenProperty = false declaredMemberScope.processPropertiesByName(name) { @@ -240,3 +250,15 @@ fun FirValueParameter.hasTypeOf(classId: ClassId, allowNullable: Boolean): Boole } private val PUBLIC_METHOD_NAMES_IN_ANY = setOf("equals", "hashCode", "toString") + +abstract class FirDelegatedMembersFilter : FirSessionComponent { + abstract fun shouldNotGenerateDelegatedMember(memberSymbolFromSuperInterface: FirCallableSymbol<*>): Boolean + + object Default : FirDelegatedMembersFilter() { + override fun shouldNotGenerateDelegatedMember(memberSymbolFromSuperInterface: FirCallableSymbol<*>): Boolean { + return false + } + } +} + +private val FirSession.delegatedMembersFilter: FirDelegatedMembersFilter by FirSession.sessionComponentAccessor() diff --git a/compiler/testData/codegen/box/collections/specialBridgeForGet.kt b/compiler/testData/codegen/box/collections/specialBridgeForGet.kt index 21c12a632ad..9c854c672c1 100644 --- a/compiler/testData/codegen/box/collections/specialBridgeForGet.kt +++ b/compiler/testData/codegen/box/collections/specialBridgeForGet.kt @@ -2,8 +2,6 @@ // IGNORE_CODEGEN_WITH_IR_FAKE_OVERRIDE_GENERATION: KT-61370 // WITH_STDLIB // FULL_JDK -// IGNORE_BACKEND_K2: ANY -// Ignore reason: KT-62334 abstract class AMap1(private val m: Map) : Map by m diff --git a/compiler/testData/codegen/box/delegation/byMiddleInterface.kt b/compiler/testData/codegen/box/delegation/byMiddleInterface.kt index 65c1d079cc7..9e316f9b5b8 100644 --- a/compiler/testData/codegen/box/delegation/byMiddleInterface.kt +++ b/compiler/testData/codegen/box/delegation/byMiddleInterface.kt @@ -1,7 +1,5 @@ // TARGET_BACKEND: JVM // JVM_TARGET: 1.8 -// IGNORE_BACKEND_K2: ANY -// Ignore reason: KT-62334 // FILE: Base.java public interface Base { diff --git a/compiler/testData/codegen/box/delegation/delegationToMap.kt b/compiler/testData/codegen/box/delegation/delegationToMap.kt index 0f7477bdab4..0ea7c3646cf 100644 --- a/compiler/testData/codegen/box/delegation/delegationToMap.kt +++ b/compiler/testData/codegen/box/delegation/delegationToMap.kt @@ -1,12 +1,3 @@ -// IGNORE_BACKEND_K2: JVM_IR, JS_IR -// FIR status: NSME: Test.remove(Ljava/lang/String;Ljava/lang/String;)Z -// FIR + JVM_IR: -// INVOKEVIRTUAL Test.remove (Ljava/lang/String;Ljava/lang/String;)Z -// => java.lang.NoSuchMethodError: Test.remove(Ljava/lang/String;Ljava/lang/String;)Z -// FE1.0 + JVM_IR: -// INVOKEVIRTUAL Test.remove (Ljava/lang/Object;Ljava/lang/Object;)Z -// => default method in java.util.Map (as expected) - // SKIP_JDK6 // TARGET_BACKEND: JVM // FULL_JDK diff --git a/compiler/testData/codegen/box/delegation/diamond.kt b/compiler/testData/codegen/box/delegation/diamond.kt index e52957331c4..80172e13a7f 100644 --- a/compiler/testData/codegen/box/delegation/diamond.kt +++ b/compiler/testData/codegen/box/delegation/diamond.kt @@ -1,7 +1,5 @@ // TARGET_BACKEND: JVM // JVM_TARGET: 1.8 -// IGNORE_BACKEND_K2: ANY -// Ignore reason: KT-62334 // FILE: Base.java public interface Base { diff --git a/compiler/testData/codegen/box/delegation/inClassDeclaration.kt b/compiler/testData/codegen/box/delegation/inClassDeclaration.kt index e38913ac117..541c697bae7 100644 --- a/compiler/testData/codegen/box/delegation/inClassDeclaration.kt +++ b/compiler/testData/codegen/box/delegation/inClassDeclaration.kt @@ -1,7 +1,5 @@ // TARGET_BACKEND: JVM // JVM_TARGET: 1.8 -// IGNORE_BACKEND_K2: ANY -// Ignore reason: KT-62334 // FILE: Base.java public interface Base { diff --git a/compiler/testData/codegen/box/delegation/mixed.kt b/compiler/testData/codegen/box/delegation/mixed.kt index bb788b95ed0..f570d9a988b 100644 --- a/compiler/testData/codegen/box/delegation/mixed.kt +++ b/compiler/testData/codegen/box/delegation/mixed.kt @@ -1,7 +1,5 @@ // TARGET_BACKEND: JVM // JVM_TARGET: 1.8 -// IGNORE_BACKEND_K2: ANY -// Ignore reason: KT-62334 // FILE: Base.java public interface Base extends KBase { diff --git a/compiler/testData/codegen/box/delegation/simple.kt b/compiler/testData/codegen/box/delegation/simple.kt index dc0ed0ce29e..d10855a639f 100644 --- a/compiler/testData/codegen/box/delegation/simple.kt +++ b/compiler/testData/codegen/box/delegation/simple.kt @@ -1,7 +1,5 @@ // TARGET_BACKEND: JVM // JVM_TARGET: 1.8 -// IGNORE_BACKEND_K2: ANY -// Ignore reason: KT-62334 // FILE: Base.java public interface Base { diff --git a/compiler/testData/codegen/box/fir/manyImplFromOneJavaInterfaceWithDelegation.kt b/compiler/testData/codegen/box/fir/manyImplFromOneJavaInterfaceWithDelegation.kt index 3ad1cd2e567..4cd8528e9f0 100644 --- a/compiler/testData/codegen/box/fir/manyImplFromOneJavaInterfaceWithDelegation.kt +++ b/compiler/testData/codegen/box/fir/manyImplFromOneJavaInterfaceWithDelegation.kt @@ -1,7 +1,5 @@ // TARGET_BACKEND: JVM_IR // JVM_TARGET: 1.8 -// IGNORE_BACKEND_K2: ANY -// Ignore reason: KT-62334 // FILE: A.java public interface A { diff --git a/compiler/testData/codegen/box/fir/manyImplFromOneJavaInterfaceWithDelegation2.kt b/compiler/testData/codegen/box/fir/manyImplFromOneJavaInterfaceWithDelegation2.kt index 91db186d9b3..28d4e328ca2 100644 --- a/compiler/testData/codegen/box/fir/manyImplFromOneJavaInterfaceWithDelegation2.kt +++ b/compiler/testData/codegen/box/fir/manyImplFromOneJavaInterfaceWithDelegation2.kt @@ -1,7 +1,5 @@ // TARGET_BACKEND: JVM_IR // JVM_TARGET: 1.8 -// IGNORE_BACKEND_K2: ANY -// Ignore reason: KT-62334 // FILE: A.java public interface A { diff --git a/compiler/testData/codegen/box/jvm8/defaults/delegationBy/javaDefaultMethod.kt b/compiler/testData/codegen/box/jvm8/defaults/delegationBy/javaDefaultMethod.kt index 5c4e2b8af4d..49c8d4b9160 100644 --- a/compiler/testData/codegen/box/jvm8/defaults/delegationBy/javaDefaultMethod.kt +++ b/compiler/testData/codegen/box/jvm8/defaults/delegationBy/javaDefaultMethod.kt @@ -1,8 +1,6 @@ // TARGET_BACKEND: JVM // JVM_TARGET: 1.8 // WITH_STDLIB -// IGNORE_BACKEND_K2: ANY -// Ignore reason: KT-62334 // FILE: javaDefaultMethod.kt @@ -23,4 +21,4 @@ public interface J { } String getK(); -} +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/traits/defaultMethod.kt b/compiler/testData/codegen/box/traits/defaultMethod.kt index edd515b76f8..b6c206a535f 100644 --- a/compiler/testData/codegen/box/traits/defaultMethod.kt +++ b/compiler/testData/codegen/box/traits/defaultMethod.kt @@ -1,7 +1,5 @@ // TARGET_BACKEND: JVM // JVM_TARGET: 1.8 -// IGNORE_BACKEND_K2: ANY -// Ignore reason: KT-62334 // MODULE: lib // FILE: A.java diff --git a/compiler/testData/ir/irText/firProblems/kt43342.fir.ir.txt b/compiler/testData/ir/irText/firProblems/kt43342.fir.ir.txt index d711a47c93b..81485426f65 100644 --- a/compiler/testData/ir/irText/firProblems/kt43342.fir.ir.txt +++ b/compiler/testData/ir/irText/firProblems/kt43342.fir.ir.txt @@ -126,6 +126,10 @@ FILE fqName: fileName:/kt43342.kt overridden: public open fun toString (): kotlin.String declared in kotlin.collections.Map $this: VALUE_PARAMETER name: type:kotlin.Any + FUN name:getOrDefault visibility:public modality:OPEN <> ($this:.ControlFlowInfo.ControlFlowInfo, V of .ControlFlowInfo>, key:K of .ControlFlowInfo, defaultValue:V of .ControlFlowInfo) returnType:V of .ControlFlowInfo + $this: VALUE_PARAMETER name: type:.ControlFlowInfo.ControlFlowInfo, V of .ControlFlowInfo> + VALUE_PARAMETER name:key index:0 type:K of .ControlFlowInfo + VALUE_PARAMETER name:defaultValue index:1 type:V of .ControlFlowInfo CLASS CLASS name:StringFlowInfo modality:FINAL visibility:public superTypes:[.ControlFlowInfo] $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.StringFlowInfo CONSTRUCTOR visibility:public <> (map:kotlin.collections.Map) returnType:.StringFlowInfo [primary]