FirClassAnySynthesizedMemberScope.kt: make it a declared member scope

Related to KT-54844, KT-58926
This commit is contained in:
Mikhail Glukhikh
2023-05-26 09:04:31 +02:00
committed by Space Team
parent 0ea0346ec1
commit 668157eb41
15 changed files with 222 additions and 72 deletions
@@ -4195,6 +4195,12 @@ public class DiagnosticCompilerTestFirTestdataTestGenerated extends AbstractDiag
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/scopes"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
}
@Test
@TestMetadata("delegatedDataClass.kt")
public void testDelegatedDataClass() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/scopes/delegatedDataClass.kt");
}
@Test
@TestMetadata("explicitOverrideOfTwoMembers.kt")
public void testExplicitOverrideOfTwoMembers() throws Exception {
@@ -4195,6 +4195,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFirTestDataTestGenerated
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/scopes"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
}
@Test
@TestMetadata("delegatedDataClass.kt")
public void testDelegatedDataClass() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/scopes/delegatedDataClass.kt");
}
@Test
@TestMetadata("explicitOverrideOfTwoMembers.kt")
public void testExplicitOverrideOfTwoMembers() throws Exception {
@@ -3699,6 +3699,11 @@ public class LazyBodyIsNotTouchedTestGenerated extends AbstractLazyBodyIsNotTouc
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/scopes"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
}
@TestMetadata("delegatedDataClass.kt")
public void testDelegatedDataClass() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/scopes/delegatedDataClass.kt");
}
@TestMetadata("explicitOverrideOfTwoMembers.kt")
public void testExplicitOverrideOfTwoMembers() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/scopes/explicitOverrideOfTwoMembers.kt");
@@ -0,0 +1,42 @@
FILE: delegatedDataClass.kt
public abstract interface AnyNeighbor : R|kotlin/Any| {
public abstract override operator fun equals(other: R|kotlin/Any?|): R|kotlin/Boolean|
public abstract override fun hashCode(): R|kotlin/Int|
public abstract override fun toString(): R|kotlin/String|
}
public final class Impl : R|AnyNeighbor| {
public constructor(): R|Impl| {
super<R|kotlin/Any|>()
}
public open override operator fun equals(other: R|kotlin/Any?|): R|kotlin/Boolean| {
^equals Boolean(true)
}
public open override fun hashCode(): R|kotlin/Int| {
^hashCode Int(0)
}
public open override fun toString(): R|kotlin/String| {
^toString String()
}
}
public final data class Data : R|AnyNeighbor| {
public constructor(i: R|Impl|): R|Data| {
super<R|kotlin/Any|>()
}
private final field $$delegate_0: R|AnyNeighbor| = R|<local>/i|
public final val i: R|Impl| = R|<local>/i|
public get(): R|Impl|
public final operator fun component1(): R|Impl|
public final fun copy(i: R|Impl| = this@R|/Data|.R|/Data.i|): R|Data|
}
@@ -0,0 +1,25 @@
// SCOPE_DUMP: Data:equals, Data:hashCode, Data:toString
interface AnyNeighbor {
override fun equals(other: Any?): Boolean
override fun hashCode(): Int
override fun toString(): String
}
class Impl : AnyNeighbor {
override fun equals(other: Any?): Boolean {
return true
}
override fun hashCode(): Int {
return 0
}
override fun toString(): String {
return ""
}
}
data class Data(val i: Impl) : AnyNeighbor by i
@@ -0,0 +1,14 @@
Data:
[Delegated]: public open override operator fun equals(other: R|kotlin/Any?|): R|kotlin/Boolean| from Use site scope of /Data [id: 0]
[Source]: public abstract override operator fun equals(other: R|kotlin/Any?|): R|kotlin/Boolean| from Use site scope of /AnyNeighbor [id: 1]
[Library]: public open operator fun equals(other: R|kotlin/Any?|): R|kotlin/Boolean| from Use site scope of kotlin/Any [id: 2]
Data:
[Delegated]: public open override fun hashCode(): R|kotlin/Int| from Use site scope of /Data [id: 0]
[Source]: public abstract override fun hashCode(): R|kotlin/Int| from Use site scope of /AnyNeighbor [id: 1]
[Library]: public open fun hashCode(): R|kotlin/Int| from Use site scope of kotlin/Any [id: 2]
Data:
[Delegated]: public open override fun toString(): R|kotlin/String| from Use site scope of /Data [id: 0]
[Source]: public abstract override fun toString(): R|kotlin/String| from Use site scope of /AnyNeighbor [id: 1]
[Library]: public open fun toString(): R|kotlin/String| from Use site scope of kotlin/Any [id: 2]
@@ -4195,6 +4195,12 @@ public class FirLightTreeDiagnosticsTestGenerated extends AbstractFirLightTreeDi
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/scopes"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
}
@Test
@TestMetadata("delegatedDataClass.kt")
public void testDelegatedDataClass() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/scopes/delegatedDataClass.kt");
}
@Test
@TestMetadata("explicitOverrideOfTwoMembers.kt")
public void testExplicitOverrideOfTwoMembers() throws Exception {
@@ -4195,6 +4195,12 @@ public class FirPsiDiagnosticTestGenerated extends AbstractFirPsiDiagnosticTest
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/scopes"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
}
@Test
@TestMetadata("delegatedDataClass.kt")
public void testDelegatedDataClass() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/scopes/delegatedDataClass.kt");
}
@Test
@TestMetadata("explicitOverrideOfTwoMembers.kt")
public void testExplicitOverrideOfTwoMembers() throws Exception {
@@ -18411,6 +18411,12 @@ public class FirLightTreeBlackBoxCodegenTestGenerated extends AbstractFirLightTr
runTest("compiler/testData/codegen/box/fir/CustomThrowableMessage.kt");
}
@Test
@TestMetadata("delegatedAndDataTogether.kt")
public void testDelegatedAndDataTogether() throws Exception {
runTest("compiler/testData/codegen/box/fir/delegatedAndDataTogether.kt");
}
@Test
@TestMetadata("differentSinceKotlin.kt")
public void testDifferentSinceKotlin() throws Exception {
@@ -18411,6 +18411,12 @@ public class FirPsiBlackBoxCodegenTestGenerated extends AbstractFirPsiBlackBoxCo
runTest("compiler/testData/codegen/box/fir/CustomThrowableMessage.kt");
}
@Test
@TestMetadata("delegatedAndDataTogether.kt")
public void testDelegatedAndDataTogether() throws Exception {
runTest("compiler/testData/codegen/box/fir/delegatedAndDataTogether.kt");
}
@Test
@TestMetadata("differentSinceKotlin.kt")
public void testDifferentSinceKotlin() throws Exception {
@@ -45,7 +45,7 @@ class FirKotlinScopeProvider(
return scopeSession.getOrBuild(klass.symbol, USE_SITE) {
val declaredScope = useSiteSession.declaredMemberScope(klass, memberRequiredPhase)
val decoratedDeclaredMemberScope = declaredMemberScopeDecorator(
val possiblyDelegatedDeclaredMemberScope = declaredMemberScopeDecorator(
klass,
declaredScope,
useSiteSession,
@@ -58,29 +58,25 @@ class FirKotlinScopeProvider(
else
FirDelegatedMemberScope(useSiteSession, scopeSession, klass, it, delegateFields)
}
val declaredMemberScopeWithPossiblySynthesizedMembers =
if (klass is FirRegularClass && !klass.isExpect && (klass.isData || klass.isInline)) {
// See also KT-58926 (we apply delegation first, and data/value classes after it)
FirClassAnySynthesizedMemberScope(useSiteSession, possiblyDelegatedDeclaredMemberScope, klass, scopeSession)
} else {
possiblyDelegatedDeclaredMemberScope
}
val scopes = lookupSuperTypes(
klass, lookupInterfaces = true, deep = false, useSiteSession = useSiteSession, substituteTypes = true
).mapNotNull { useSiteSuperType ->
useSiteSuperType.scopeForSupertype(useSiteSession, scopeSession, klass, memberRequiredPhase = memberRequiredPhase)
}
val useSiteMemberScope = FirClassUseSiteMemberScope(
FirClassUseSiteMemberScope(
klass,
useSiteSession,
scopes,
decoratedDeclaredMemberScope,
declaredMemberScopeWithPossiblySynthesizedMembers,
)
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
}
}
}
@@ -6,12 +6,10 @@
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
@@ -19,19 +17,22 @@ 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.FirRegularClass
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.ScopeSession
import org.jetbrains.kotlin.fir.resolve.defaultType
import org.jetbrains.kotlin.fir.resolve.lookupSuperTypes
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.scopes.FirContainingNamesAwareScope
import org.jetbrains.kotlin.fir.scopes.scopeForSupertype
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
@@ -41,86 +42,85 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.utils.addToStdlib.shouldNotBeCalled
/**
* This declared scope wrapper is created for data/value classes and provides Any method stubs, if necessary
*/
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 declaredMemberScope: FirContainingNamesAwareScope,
klass: FirRegularClass,
scopeSession: ScopeSession,
) : FirContainingNamesAwareScope() {
private val lookupTag = klass.symbol.toLookupTag()
private val baseModuleData = klass.moduleData
private val dispatchReceiverType = klass.defaultType()
private val synthesizedCache = session.synthesizedStorage.synthesizedCacheByScope.getValue(lookupTag, null)
private val synthesizedOverrides = mutableMapOf<FirNamedFunctionSymbol, FirNamedFunctionSymbol>()
private val synthesizedSource = klass.source?.fakeElement(KtFakeSourceElementKind.DataClassGeneratedMembers)
private val synthesizedSource = classSource?.fakeElement(KtFakeSourceElementKind.DataClassGeneratedMembers)
private val superKlassScope = lookupSuperTypes(
klass, lookupInterfaces = false, deep = false, useSiteSession = session, substituteTypes = true
).firstOrNull()?.scopeForSupertype(session, scopeSession, klass, memberRequiredPhase = FirResolvePhase.TYPES)
override fun processClassifiersByNameWithSubstitution(name: Name, processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit) {
useSiteMemberScope.processClassifiersByNameWithSubstitution(name, processor)
declaredMemberScope.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)
declaredMemberScope.processDeclaredConstructors(processor)
}
override fun getCallableNames(): Set<Name> {
return useSiteMemberScope.getCallableNames()
return declaredMemberScope.getCallableNames()
}
override fun getClassifierNames(): Set<Name> {
return useSiteMemberScope.getClassifierNames()
return declaredMemberScope.getClassifierNames()
}
override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) {
useSiteMemberScope.processPropertiesByName(name, processor)
declaredMemberScope.processPropertiesByName(name, processor)
}
override fun processFunctionsByName(name: Name, processor: (FirNamedFunctionSymbol) -> Unit) {
if (name !in ANY_MEMBER_NAMES) {
useSiteMemberScope.processFunctionsByName(name, processor)
declaredMemberScope.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)
var synthesizedFunctionIsNeeded = true
declaredMemberScope.processFunctionsByName(name) process@{ fromDeclaredScope ->
if (fromDeclaredScope.matchesSomeAnyMember(name)) {
// TODO: should we handle fromDeclaredScope.origin == FirDeclarationOrigin.Delegated somehow?
// See also KT-58926
synthesizedFunctionIsNeeded = false
}
processor(fromDeclaredScope)
}
if (!synthesizedFunctionIsNeeded) return
superKlassScope?.processFunctionsByName(name) { fromSuperType ->
if (synthesizedFunctionIsNeeded) {
if (fromSuperType.rawStatus.modality == Modality.FINAL && fromSuperType.matchesSomeAnyMember(name)) {
synthesizedFunctionIsNeeded = false
}
}
}
if (!synthesizedFunctionIsNeeded) return
processor(synthesizedCache.synthesizedFunction.getValue(name, this))
}
private fun FirNamedFunctionSymbol.matchesSomeAnyMember(name: Name): Boolean {
return when (name) {
OperatorNameConventions.HASH_CODE, OperatorNameConventions.TO_STRING -> {
valueParameterSymbols.isEmpty() && !isExtension && fir.contextReceivers.isEmpty()
}
else -> {
lazyResolveToPhase(FirResolvePhase.TYPES)
fir.isEquals()
}
}
}
internal fun generateSyntheticFunctionByName(name: Name): FirNamedFunctionSymbol =
@@ -191,7 +191,7 @@ class FirSynthesizedStorage(val session: FirSession) : FirSessionComponent {
cachesFactory.createCache { _ -> SynthesizedCache(session.firCachesFactory) }
class SynthesizedCache(cachesFactory: FirCachesFactory) {
val synthesizedFunctionAndOverrides: FirCache<Name, FirNamedFunctionSymbol, FirClassAnySynthesizedMemberScope> =
val synthesizedFunction: FirCache<Name, FirNamedFunctionSymbol, FirClassAnySynthesizedMemberScope> =
cachesFactory.createCache { name, scope -> scope.generateSyntheticFunctionByName(name) }
}
}
@@ -0,0 +1,20 @@
// TARGET_BACKEND: JVM_IR
// ISSUE: KT-58926
fun box(): String {
val i1 = Impl()
val i2 = Impl()
val d1 = Data(i1, 1)
val d2 = Data(i2, 2)
return if (d1 != d2) "FAIL: should be equal" else "OK"
}
interface AnyNeighbor {
override fun equals(other: Any?): Boolean
}
class Impl : AnyNeighbor {
override fun equals(other: Any?): Boolean = true
}
data class Data(val i: Impl, val j: Int) : AnyNeighbor by i
@@ -18411,6 +18411,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/fir/CustomThrowableMessage.kt");
}
@Test
@TestMetadata("delegatedAndDataTogether.kt")
public void testDelegatedAndDataTogether() throws Exception {
runTest("compiler/testData/codegen/box/fir/delegatedAndDataTogether.kt");
}
@Test
@TestMetadata("differentSinceKotlin.kt")
public void testDifferentSinceKotlin() throws Exception {
@@ -18411,6 +18411,12 @@ public class IrBlackBoxCodegenWithIrInlinerTestGenerated extends AbstractIrBlack
runTest("compiler/testData/codegen/box/fir/CustomThrowableMessage.kt");
}
@Test
@TestMetadata("delegatedAndDataTogether.kt")
public void testDelegatedAndDataTogether() throws Exception {
runTest("compiler/testData/codegen/box/fir/delegatedAndDataTogether.kt");
}
@Test
@TestMetadata("differentSinceKotlin.kt")
public void testDifferentSinceKotlin() throws Exception {