K2: introduce platform-dependent filtering for non-JVM platforms

This commit fixes a false negative in testData/cli/metadata/getOrDefault
Related to KT-57268
This commit is contained in:
Mikhail Glukhikh
2024-01-30 11:08:06 +01:00
committed by Space Team
parent 7599ff0ef1
commit ed246d372b
4 changed files with 62 additions and 13 deletions
@@ -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)
}
@@ -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<Name> = declaredMemberScope.getCallableNames()
override fun getClassifierNames(): Set<Name> = 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<String>
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,
+4 -1
View File
@@ -1 +1,4 @@
OK
compiler/testData/cli/metadata/getOrDefault.kt:2:38: error: unresolved reference 'getOrDefault'.
fun foo(map: Map<String, Int>) = map.getOrDefault("", 0)
^
COMPILATION_ERROR
@@ -12,4 +12,4 @@ public expect abstract class AbstractMutableMap<K, V> : MutableMap<K, V> {
import java.util.AbstractMap
public actual abstract class <!NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS, NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS!>AbstractMutableMap<!><K, V>() : MutableMap<K, V>, AbstractMap<K, V>()
public actual abstract class <!NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS!>AbstractMutableMap<!><K, V>() : MutableMap<K, V>, AbstractMap<K, V>()