From ed246d372b8cb0e2e9d3af5d11691347adf393fd Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Tue, 30 Jan 2024 11:08:06 +0100 Subject: [PATCH] K2: introduce platform-dependent filtering for non-JVM platforms This commit fixes a false negative in testData/cli/metadata/getOrDefault Related to KT-57268 --- .../jvm/FirJvmPlatformDeclarationFilter.kt | 12 +--- .../fir/scopes/FirKotlinScopeProvider.kt | 56 ++++++++++++++++++- .../testData/cli/metadata/getOrDefault.out | 5 +- ...plicitActualFakeOverride_AbstractMap.ll.kt | 2 +- 4 files changed, 62 insertions(+), 13 deletions(-) diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/scopes/jvm/FirJvmPlatformDeclarationFilter.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/scopes/jvm/FirJvmPlatformDeclarationFilter.kt index 12e47e82292..bbc66d5a58c 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/scopes/jvm/FirJvmPlatformDeclarationFilter.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/scopes/jvm/FirJvmPlatformDeclarationFilter.kt @@ -5,20 +5,14 @@ package org.jetbrains.kotlin.fir.scopes.jvm -import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction -import org.jetbrains.kotlin.fir.declarations.hasAnnotation +import org.jetbrains.kotlin.fir.scopes.FirPlatformDeclarationFilter import org.jetbrains.kotlin.fir.scopes.FirTypeScope -import org.jetbrains.kotlin.name.Name internal object FirJvmPlatformDeclarationFilter { fun isFunctionAvailable(function: FirSimpleFunction, javaClassScope: FirTypeScope, session: FirSession): Boolean { - // Optimization: only run the below logic for functions named "getOrDefault" and "remove", since only two functions with these names - // in kotlin.collections.Map are currently annotated with @PlatformDependent. - if (function.name !in namesToCheck) return true - - if (!function.hasAnnotation(StandardNames.FqNames.platformDependentClassId, session)) return true + if (FirPlatformDeclarationFilter.isFunctionAvailable(function, session)) return true var isFunctionPresentInJavaAnalogue = false val jvmDescriptorOfKotlinFunction = function.computeJvmDescriptor() @@ -29,6 +23,4 @@ internal object FirJvmPlatformDeclarationFilter { } return isFunctionPresentInJavaAnalogue } - - private val namesToCheck = listOf("getOrDefault", "remove").map(Name::identifier) } diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/FirKotlinScopeProvider.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/FirKotlinScopeProvider.kt index d59ad4c4869..3dc79a6c5fe 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/FirKotlinScopeProvider.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/FirKotlinScopeProvider.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.fir.scopes +import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSessionComponent @@ -12,6 +13,8 @@ import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.declarations.FirResolvePhase +import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction +import org.jetbrains.kotlin.fir.declarations.hasAnnotation import org.jetbrains.kotlin.fir.declarations.utils.delegateFields import org.jetbrains.kotlin.fir.declarations.utils.isData import org.jetbrains.kotlin.fir.declarations.utils.isExpect @@ -23,9 +26,14 @@ import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap import org.jetbrains.kotlin.fir.scopes.impl.* import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirClassifierSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhaseWithCallableMembers import org.jetbrains.kotlin.fir.types.* +import org.jetbrains.kotlin.name.Name class FirKotlinScopeProvider( val declaredMemberScopeDecorator: ( @@ -34,7 +42,9 @@ class FirKotlinScopeProvider( useSiteSession: FirSession, scopeSession: ScopeSession, memberRequiredPhase: FirResolvePhase?, - ) -> FirContainingNamesAwareScope = { _, declaredMemberScope, _, _, _ -> declaredMemberScope } + ) -> FirContainingNamesAwareScope = { _, declaredMemberScope, session, _, _ -> + PlatformDependentFilteringScope(declaredMemberScope, session) + } ) : FirScopeProvider(), FirSessionComponent { override fun getUseSiteMemberScope( klass: FirClass, @@ -109,8 +119,52 @@ class FirKotlinScopeProvider( ): FirContainingNamesAwareScope? { return useSiteSession.nestedClassifierScope(klass) } + + class PlatformDependentFilteringScope( + val declaredMemberScope: FirContainingNamesAwareScope, + val session: FirSession, + ) : FirContainingNamesAwareScope() { + override fun getCallableNames(): Set = declaredMemberScope.getCallableNames() + + override fun getClassifierNames(): Set = declaredMemberScope.getClassifierNames() + + override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) { + declaredMemberScope.processPropertiesByName(name, processor) + } + + override fun processClassifiersByNameWithSubstitution(name: Name, processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit) { + declaredMemberScope.processClassifiersByNameWithSubstitution(name, processor) + } + + override fun processDeclaredConstructors(processor: (FirConstructorSymbol) -> Unit) { + declaredMemberScope.processDeclaredConstructors(processor) + } + + override fun processFunctionsByName(name: Name, processor: (FirNamedFunctionSymbol) -> Unit) { + declaredMemberScope.processFunctionsByName(name) { + if (FirPlatformDeclarationFilter.isFunctionAvailable(it.fir, session)) { + processor(it) + } + } + } + + override fun mayContainName(name: Name): Boolean = declaredMemberScope.mayContainName(name) + + override val scopeOwnerLookupNames: List + get() = declaredMemberScope.scopeOwnerLookupNames + } } +object FirPlatformDeclarationFilter { + fun isFunctionAvailable(function: FirSimpleFunction, session: FirSession): Boolean { + // Optimization: only check the annotations for functions named "getOrDefault" and "remove", + // since only two functions with these names in kotlin.collections.Map are currently annotated with @PlatformDependent. + // This also allows to optimize more heavyweight FirJvmPlatformDeclarationFilter as it uses this function + return function.name !in namesToCheck || !function.hasAnnotation(StandardNames.FqNames.platformDependentClassId, session) + } + + private val namesToCheck = listOf("getOrDefault", "remove").map(Name::identifier) +} data class ConeSubstitutionScopeKey( val lookupTag: ConeClassLikeLookupTag, diff --git a/compiler/testData/cli/metadata/getOrDefault.out b/compiler/testData/cli/metadata/getOrDefault.out index d86bac9de59..f2d237f4cd8 100644 --- a/compiler/testData/cli/metadata/getOrDefault.out +++ b/compiler/testData/cli/metadata/getOrDefault.out @@ -1 +1,4 @@ -OK +compiler/testData/cli/metadata/getOrDefault.kt:2:38: error: unresolved reference 'getOrDefault'. +fun foo(map: Map) = map.getOrDefault("", 0) + ^ +COMPILATION_ERROR diff --git a/compiler/testData/diagnostics/tests/multiplatform/scopes/implicitActualFakeOverride_AbstractMap.ll.kt b/compiler/testData/diagnostics/tests/multiplatform/scopes/implicitActualFakeOverride_AbstractMap.ll.kt index edfc21b21c6..3a83499727c 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/scopes/implicitActualFakeOverride_AbstractMap.ll.kt +++ b/compiler/testData/diagnostics/tests/multiplatform/scopes/implicitActualFakeOverride_AbstractMap.ll.kt @@ -12,4 +12,4 @@ public expect abstract class AbstractMutableMap : MutableMap { import java.util.AbstractMap -public actual abstract class AbstractMutableMap() : MutableMap, AbstractMap() +public actual abstract class AbstractMutableMap() : MutableMap, AbstractMap()