[FIR] Don't generate delegated members for java methods with default implementation

^KT-62334 Fixed
This commit is contained in:
Dmitriy Novozhilov
2023-10-05 12:04:37 +03:00
committed by Space Team
parent 5857e6cc5d
commit 61ec143b74
16 changed files with 78 additions and 30 deletions
@@ -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 --------------------------
@@ -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)
}
}
@@ -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)
}
}
@@ -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()
@@ -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<K1, V1>(private val m: Map<K1, V1>) : Map<K1, V1> by m
@@ -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 {
@@ -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
-2
View File
@@ -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 {
@@ -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 {
-2
View File
@@ -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 {
-2
View File
@@ -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 {
@@ -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 {
@@ -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 {
@@ -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();
}
}
-2
View File
@@ -1,7 +1,5 @@
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// IGNORE_BACKEND_K2: ANY
// Ignore reason: KT-62334
// MODULE: lib
// FILE: A.java
@@ -126,6 +126,10 @@ FILE fqName:<root> fileName:/kt43342.kt
overridden:
public open fun toString (): kotlin.String declared in kotlin.collections.Map
$this: VALUE_PARAMETER name:<this> type:kotlin.Any
FUN name:getOrDefault visibility:public modality:OPEN <> ($this:<root>.ControlFlowInfo<K of <root>.ControlFlowInfo, V of <root>.ControlFlowInfo>, key:K of <root>.ControlFlowInfo, defaultValue:V of <root>.ControlFlowInfo) returnType:V of <root>.ControlFlowInfo
$this: VALUE_PARAMETER name:<this> type:<root>.ControlFlowInfo<K of <root>.ControlFlowInfo, V of <root>.ControlFlowInfo>
VALUE_PARAMETER name:key index:0 type:K of <root>.ControlFlowInfo
VALUE_PARAMETER name:defaultValue index:1 type:V of <root>.ControlFlowInfo
CLASS CLASS name:StringFlowInfo modality:FINAL visibility:public superTypes:[<root>.ControlFlowInfo<kotlin.String, kotlin.String>]
$this: VALUE_PARAMETER INSTANCE_RECEIVER name:<this> type:<root>.StringFlowInfo
CONSTRUCTOR visibility:public <> (map:kotlin.collections.Map<kotlin.String, kotlin.String>) returnType:<root>.StringFlowInfo [primary]