K2: implement FirClassAnySynthesizedMemberScope #KT-54844 Fixed

This commit is contained in:
Mikhail Glukhikh
2022-11-09 17:55:19 +01:00
committed by Space Team
parent c898b264ba
commit 2a825f8df1
10 changed files with 230 additions and 24 deletions
@@ -16,7 +16,7 @@ import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.fir.declarations.utils.hasBody
import org.jetbrains.kotlin.fir.declarations.utils.isInterface
import org.jetbrains.kotlin.fir.declarations.utils.isOverride
import org.jetbrains.kotlin.fir.resolve.isEquals
import org.jetbrains.kotlin.fir.symbols.impl.isEquals
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.util.OperatorNameConventions.TO_STRING
@@ -22,9 +22,9 @@ import org.jetbrains.kotlin.fir.declarations.utils.*
import org.jetbrains.kotlin.fir.expressions.toResolvedCallableSymbol
import org.jetbrains.kotlin.fir.resolve.defaultType
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.resolve.isEquals
import org.jetbrains.kotlin.fir.resolve.lookupSuperTypes
import org.jetbrains.kotlin.fir.symbols.impl.FirValueParameterSymbol
import org.jetbrains.kotlin.fir.symbols.impl.isEquals
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.impl.FirImplicitAnyTypeRef
import org.jetbrains.kotlin.lexer.KtTokens
@@ -73,6 +73,7 @@ fun FirSession.registerCommonComponents(languageVersionSettings: LanguageVersion
register(FirSubstitutionOverrideStorage::class, FirSubstitutionOverrideStorage(this))
register(FirIntersectionOverrideStorage::class, FirIntersectionOverrideStorage(this))
register(FirSynthesizedStorage::class, FirSynthesizedStorage(this))
register(FirGeneratedMemberDeclarationsStorage::class, FirGeneratedMemberDeclarationsStorage(this))
register(FirSamConstructorStorage::class, FirSamConstructorStorage(this))
register(FirOverrideService::class, FirOverrideService(this))
@@ -12,8 +12,7 @@ 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.utils.delegateFields
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
import org.jetbrains.kotlin.fir.declarations.utils.*
import org.jetbrains.kotlin.fir.resolve.*
import org.jetbrains.kotlin.fir.resolve.substitution.ConeRawScopeSubstitutor
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
@@ -65,13 +64,23 @@ class FirKotlinScopeProvider(
).mapNotNull { useSiteSuperType ->
useSiteSuperType.scopeForSupertype(useSiteSession, scopeSession, klass, memberRequiredPhase = memberRequiredPhase)
}
FirClassUseSiteMemberScope(
val useSiteMemberScope = FirClassUseSiteMemberScope(
klass,
useSiteSession,
scopes,
decoratedDeclaredMemberScope,
)
if (klass is FirRegularClass && !klass.isExpect && (klass.isData || klass.isInline)) {
val lookupTag = klass.symbol.toLookupTag()
scopeSession.getOrBuild(lookupTag, AnySynthesizedScopeKey(lookupTag)) {
FirClassAnySynthesizedMemberScope(
useSiteSession, useSiteMemberScope, lookupTag,
klass.moduleData, klass.defaultType(), klass.source
)
}
} else {
useSiteMemberScope
}
}
}
@@ -110,6 +119,10 @@ data class ConeSubstitutionScopeKey(
val derivedClassLookupTag: ConeClassLikeLookupTag?
) : ScopeSessionKey<FirClass, FirClassSubstitutionScope>()
data class AnySynthesizedScopeKey(
val lookupTag: ConeClassLikeLookupTag
) : ScopeSessionKey<ConeClassLikeLookupTag, FirClassAnySynthesizedMemberScope>()
fun FirClass.unsubstitutedScope(
useSiteSession: FirSession,
scopeSession: ScopeSession,
@@ -0,0 +1,199 @@
/*
* 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.impl
import org.jetbrains.kotlin.KtFakeSourceElementKind
import org.jetbrains.kotlin.KtSourceElement
import org.jetbrains.kotlin.descriptors.EffectiveVisibility
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fakeElement
import org.jetbrains.kotlin.fir.FirModuleData
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.FirSessionComponent
import org.jetbrains.kotlin.fir.caches.FirCache
import org.jetbrains.kotlin.fir.caches.FirCachesFactory
import org.jetbrains.kotlin.fir.caches.createCache
import org.jetbrains.kotlin.fir.caches.firCachesFactory
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.fir.declarations.builder.FirSimpleFunctionBuilder
import org.jetbrains.kotlin.fir.declarations.builder.buildSimpleFunction
import org.jetbrains.kotlin.fir.declarations.builder.buildValueParameter
import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusImpl
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.scopes.FirTypeScope
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
import org.jetbrains.kotlin.fir.types.impl.FirImplicitBooleanTypeRef
import org.jetbrains.kotlin.fir.types.impl.FirImplicitIntTypeRef
import org.jetbrains.kotlin.fir.types.impl.FirImplicitNullableAnyTypeRef
import org.jetbrains.kotlin.fir.types.impl.FirImplicitStringTypeRef
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.utils.addToStdlib.shouldNotBeCalled
class FirClassAnySynthesizedMemberScope(
session: FirSession,
private val useSiteMemberScope: FirClassUseSiteMemberScope,
private val lookupTag: ConeClassLikeLookupTag,
private val baseModuleData: FirModuleData,
private val dispatchReceiverType: ConeClassLikeType,
classSource: KtSourceElement?,
) : FirTypeScope() {
private val synthesizedCache = session.synthesizedStorage.synthesizedCacheByScope.getValue(lookupTag, null)
private val synthesizedOverrides = mutableMapOf<FirNamedFunctionSymbol, FirNamedFunctionSymbol>()
private val synthesizedSource = classSource?.fakeElement(KtFakeSourceElementKind.DataClassGeneratedMembers)
override fun processClassifiersByNameWithSubstitution(name: Name, processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit) {
useSiteMemberScope.processClassifiersByNameWithSubstitution(name, processor)
}
override fun processDeclaredConstructors(processor: (FirConstructorSymbol) -> Unit) {
useSiteMemberScope.processDeclaredConstructors(processor)
}
override fun processDirectOverriddenPropertiesWithBaseScope(
propertySymbol: FirPropertySymbol,
processor: (FirPropertySymbol, FirTypeScope) -> ProcessorAction
): ProcessorAction {
return useSiteMemberScope.processDirectOverriddenPropertiesWithBaseScope(propertySymbol, processor)
}
override fun processDirectOverriddenFunctionsWithBaseScope(
functionSymbol: FirNamedFunctionSymbol,
processor: (FirNamedFunctionSymbol, FirTypeScope) -> ProcessorAction,
): ProcessorAction {
val overridden = synthesizedOverrides[functionSymbol]
?: return useSiteMemberScope.processDirectOverriddenFunctionsWithBaseScope(functionSymbol, processor)
return processor(overridden, useSiteMemberScope)
}
override fun getCallableNames(): Set<Name> {
return useSiteMemberScope.getCallableNames()
}
override fun getClassifierNames(): Set<Name> {
return useSiteMemberScope.getClassifierNames()
}
override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) {
useSiteMemberScope.processPropertiesByName(name, processor)
}
override fun processFunctionsByName(name: Name, processor: (FirNamedFunctionSymbol) -> Unit) {
if (name !in ANY_MEMBER_NAMES) {
useSiteMemberScope.processFunctionsByName(name, processor)
return
}
useSiteMemberScope.processFunctionsByName(name) { fromUseSiteScope ->
if (fromUseSiteScope.rawStatus.modality == Modality.FINAL) {
processor(fromUseSiteScope)
} else {
val matchedSomeAnyMember = when (name) {
OperatorNameConventions.HASH_CODE, OperatorNameConventions.TO_STRING -> {
fromUseSiteScope.valueParameterSymbols.isEmpty() && !fromUseSiteScope.isExtension &&
fromUseSiteScope.fir.contextReceivers.isEmpty()
}
else -> {
fromUseSiteScope.lazyResolveToPhase(FirResolvePhase.TYPES)
fromUseSiteScope.fir.isEquals()
}
}
val hasSameReceiver =
dispatchReceiverType.lookupTag == (fromUseSiteScope.dispatchReceiverType as? ConeClassLikeType)?.lookupTag
if (!matchedSomeAnyMember || hasSameReceiver) {
processor(fromUseSiteScope)
} else {
val synthesized = synthesizedCache.synthesizedFunctionAndOverrides.getValue(name, this)
synthesizedOverrides[synthesized] = fromUseSiteScope
processor(synthesized)
}
}
}
}
internal fun generateSyntheticFunctionByName(name: Name): FirNamedFunctionSymbol =
when (name) {
OperatorNameConventions.EQUALS -> generateEqualsFunction()
OperatorNameConventions.HASH_CODE -> generateHashCodeFunction()
OperatorNameConventions.TO_STRING -> generateToStringFunction()
else -> shouldNotBeCalled()
}.symbol
private fun generateEqualsFunction(): FirSimpleFunction =
buildSimpleFunction {
generateSyntheticFunction(OperatorNameConventions.EQUALS, isOperator = true)
returnTypeRef = FirImplicitBooleanTypeRef(source)
this.valueParameters.add(
buildValueParameter {
this.name = Name.identifier("other")
origin = FirDeclarationOrigin.Synthetic
moduleData = baseModuleData
this.returnTypeRef = FirImplicitNullableAnyTypeRef(null)
this.symbol = FirValueParameterSymbol(this.name)
containingFunctionSymbol = this@buildSimpleFunction.symbol
isCrossinline = false
isNoinline = false
isVararg = false
}
)
}
private fun generateHashCodeFunction(): FirSimpleFunction =
buildSimpleFunction {
generateSyntheticFunction(OperatorNameConventions.HASH_CODE)
returnTypeRef = FirImplicitIntTypeRef(source)
}
private fun generateToStringFunction(): FirSimpleFunction =
buildSimpleFunction {
generateSyntheticFunction(OperatorNameConventions.TO_STRING)
returnTypeRef = FirImplicitStringTypeRef(source)
}
private fun FirSimpleFunctionBuilder.generateSyntheticFunction(
name: Name,
isOperator: Boolean = false,
) {
this.source = synthesizedSource
moduleData = baseModuleData
origin = FirDeclarationOrigin.Synthetic
this.name = name
status = FirResolvedDeclarationStatusImpl(Visibilities.Public, Modality.OPEN, EffectiveVisibility.Public).apply {
this.isOperator = isOperator
}
symbol = FirNamedFunctionSymbol(CallableId(lookupTag.classId, name))
dispatchReceiverType = this@FirClassAnySynthesizedMemberScope.dispatchReceiverType
}
companion object {
private val ANY_MEMBER_NAMES = hashSetOf(
OperatorNameConventions.HASH_CODE, OperatorNameConventions.EQUALS, OperatorNameConventions.TO_STRING
)
}
}
class FirSynthesizedStorage(val session: FirSession) : FirSessionComponent {
private val cachesFactory = session.firCachesFactory
val synthesizedCacheByScope: FirCache<ConeClassLikeLookupTag, SynthesizedCache, Nothing?> =
cachesFactory.createCache { _ -> SynthesizedCache(session.firCachesFactory) }
class SynthesizedCache(cachesFactory: FirCachesFactory) {
val synthesizedFunctionAndOverrides: FirCache<Name, FirNamedFunctionSymbol, FirClassAnySynthesizedMemberScope> =
cachesFactory.createCache { name, scope -> scope.generateSyntheticFunctionByName(name) }
}
}
private val FirSession.synthesizedStorage: FirSynthesizedStorage by FirSession.sessionComponentAccessor()
@@ -30,10 +30,7 @@ import org.jetbrains.kotlin.fir.scopes.getFunctions
import org.jetbrains.kotlin.fir.scopes.impl.declaredMemberScope
import org.jetbrains.kotlin.fir.scopes.impl.toConeType
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.name.StandardClassIds
import org.jetbrains.kotlin.types.ConstantValueKind
@@ -87,12 +87,3 @@ var FirConstructor.originalConstructorIfTypeAlias: FirConstructor? by FirDeclara
val FirConstructorSymbol.isTypeAliasedConstructor: Boolean
get() = fir.originalConstructorIfTypeAlias != null
fun FirSimpleFunction.isEquals(): Boolean {
if (name != OperatorNameConventions.EQUALS) return false
if (valueParameters.size != 1) return false
if (contextReceivers.isNotEmpty()) return false
if (receiverParameter != null) return false
val parameter = valueParameters.first()
return parameter.returnTypeRef.isNullableAny
}
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.mpp.CallableSymbolMarker
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.util.OperatorNameConventions
abstract class FirCallableSymbol<D : FirCallableDeclaration> : FirBasedSymbol<D>(), CallableSymbolMarker {
abstract val callableId: CallableId
@@ -95,3 +96,12 @@ val FirCallableSymbol<*>.isExtension: Boolean
is FirProperty -> fir.receiverParameter != null
is FirVariable -> false
}
fun FirSimpleFunction.isEquals(): Boolean {
if (name != OperatorNameConventions.EQUALS) return false
if (valueParameters.size != 1) return false
if (contextReceivers.isNotEmpty()) return false
if (receiverParameter != null) return false
val parameter = valueParameters.first()
return parameter.returnTypeRef.isNullableAny
}
-2
View File
@@ -1,5 +1,3 @@
// IGNORE_BACKEND_K2: JVM_IR, JS_IR, NATIVE
// FIR status: [IR VALIDATION] Duplicate IR node: FUN GENERATED_DATA_CLASS_MEMBER name:toString
// CHECK_BYTECODE_LISTING
// FIR_IDENTICAL
// WITH_STDLIB
@@ -1,6 +1,3 @@
// IGNORE_BACKEND_K2: JVM_IR, JS_IR, NATIVE
// FIR status: [IR VALIDATION] Duplicate IR node: FUN GENERATED_DATA_CLASS_MEMBER name:equals
interface A {
fun Any.equals(other: Any?): Boolean = false
fun Any.hashCode(): Int = 0