K2: implement FirClassAnySynthesizedMemberScope #KT-54844 Fixed
This commit is contained in:
committed by
Space Team
parent
c898b264ba
commit
2a825f8df1
+1
-1
@@ -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
|
||||
|
||||
|
||||
+1
-1
@@ -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))
|
||||
|
||||
+17
-4
@@ -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,
|
||||
|
||||
+199
@@ -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()
|
||||
+1
-4
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user