diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaScopeProvider.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaScopeProvider.kt index 85039b63e62..4d4ba24f64c 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaScopeProvider.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaScopeProvider.kt @@ -91,7 +91,7 @@ class JavaScopeProvider( lookupSuperTypes(regularClass, lookupInterfaces = true, deep = false, useSiteSession = useSiteSession) val superTypeScopes = superTypes.mapNotNull { - it.scopeForSupertype(useSiteSession, scopeSession, subClass = regularClass, declaredScope, delegateFields = null) + it.scopeForSupertype(useSiteSession, scopeSession, subClass = regularClass) } JavaClassUseSiteMemberScope( diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/FirKotlinScopeProvider.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/FirKotlinScopeProvider.kt index 200b23fabac..4ce5cbf79ca 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/FirKotlinScopeProvider.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/FirKotlinScopeProvider.kt @@ -10,19 +10,15 @@ import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.declarations.FirField import org.jetbrains.kotlin.fir.declarations.FirRegularClass -import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.fir.declarations.utils.isExpect import org.jetbrains.kotlin.fir.declarations.utils.isSynthetic import org.jetbrains.kotlin.fir.resolve.* import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap -import org.jetbrains.kotlin.fir.resolve.transformers.ensureResolved import org.jetbrains.kotlin.fir.scopes.impl.* import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol -import org.jetbrains.kotlin.fir.typeContext import org.jetbrains.kotlin.fir.types.* -import org.jetbrains.kotlin.name.CallableId class FirKotlinScopeProvider( val declaredMemberScopeDecorator: ( @@ -39,13 +35,21 @@ class FirKotlinScopeProvider( ): FirTypeScope { return scopeSession.getOrBuild(klass.symbol, USE_SITE) { val declaredScope = useSiteSession.declaredMemberScope(klass) - val decoratedDeclaredMemberScope = - declaredMemberScopeDecorator(klass, declaredScope, useSiteSession, scopeSession) val delegateFields = klass.declarations.filterIsInstance().filter { it.isSynthetic } + + val decoratedDeclaredMemberScope = + declaredMemberScopeDecorator(klass, declaredScope, useSiteSession, scopeSession).let { + if (delegateFields.isEmpty()) + it + else + FirNewDelegatedMemberScope(useSiteSession, scopeSession, klass, it, delegateFields) + } + + val scopes = lookupSuperTypes(klass, lookupInterfaces = true, deep = false, useSiteSession = useSiteSession) .mapNotNull { useSiteSuperType -> - useSiteSuperType.scopeForSupertype(useSiteSession, scopeSession, klass, decoratedDeclaredMemberScope, delegateFields) + useSiteSuperType.scopeForSupertype(useSiteSession, scopeSession, klass) } FirClassUseSiteMemberScope( useSiteSession, @@ -79,8 +83,6 @@ data class ConeSubstitutionScopeKey( val lookupTag: ConeClassLikeLookupTag, val isFromExpectClass: Boolean, val substitutor: ConeSubstitutor ) : ScopeSessionKey() -data class DelegatedMemberScopeKey(val callableId: CallableId) : ScopeSessionKey() - fun FirClass.unsubstitutedScope( useSiteSession: FirSession, scopeSession: ScopeSession, @@ -107,25 +109,19 @@ fun ConeKotlinType.scopeForSupertype( useSiteSession: FirSession, scopeSession: ScopeSession, subClass: FirClass, - declaredMemberScope: FirScope, - delegateFields: List?, ): FirTypeScope? { if (this !is ConeClassLikeType) return null if (this is ConeClassErrorType) return null val symbol = lookupTag.toSymbol(useSiteSession) return if (symbol is FirRegularClassSymbol) { - val delegateField = delegateFields?.find { - it.ensureResolved(FirResolvePhase.TYPES, useSiteSession) - useSiteSession.typeContext.equalTypes(it.returnTypeRef.coneType, this) - } - symbol.fir.scopeForSupertype( + symbol.fir.scopeForClassImpl( substitutor(symbol, this, useSiteSession), - useSiteSession, scopeSession, delegateField, - subClass = subClass, - declaredMemberScope - ).let { - it as? FirTypeScope ?: error("$it is expected to be FirOverrideAwareScope") - } + useSiteSession, + scopeSession, + skipPrivateMembers = true, + classFirDispatchReceiver = subClass, + isFromExpectClass = (subClass as? FirRegularClass)?.isExpect == true + ) } else { null } @@ -137,30 +133,6 @@ private fun substitutor(symbol: FirRegularClassSymbol, type: ConeClassLikeType, return substitutorByMap(originalSubstitution, useSiteSession) } -fun FirClass.scopeForSupertype( - substitutor: ConeSubstitutor, - useSiteSession: FirSession, - scopeSession: ScopeSession, - delegateField: FirField?, - subClass: FirClass, - declaredMemberScope: FirScope, -): FirTypeScope = scopeForClassImpl( - substitutor, - useSiteSession, - scopeSession, - skipPrivateMembers = true, - classFirDispatchReceiver = subClass, - isFromExpectClass = (subClass as? FirRegularClass)?.isExpect == true -).let { - if (delegateField != null) { - scopeSession.getOrBuild(delegateField, DelegatedMemberScopeKey(delegateField.symbol.callableId)) { - FirDelegatedMemberScope(it, useSiteSession, subClass, delegateField, declaredMemberScope) - } - } else { - it - } -} - private fun FirClass.scopeForClassImpl( substitutor: ConeSubstitutor, useSiteSession: FirSession, @@ -176,7 +148,7 @@ private fun FirClass.scopeForClassImpl( this, ConeSubstitutionScopeKey(classFirDispatchReceiver.symbol.toLookupTag(), isFromExpectClass, substitutor) ) { FirClassSubstitutionScope( - useSiteSession, basicScope, substitutor, classFirDispatchReceiver.defaultType(), + useSiteSession, basicScope, substitutor, classFirDispatchReceiver.defaultType(), skipPrivateMembers, makeExpect = isFromExpectClass ) } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirNewDelegatedMemberScope.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirNewDelegatedMemberScope.kt new file mode 100644 index 00000000000..6b84cc72fcb --- /dev/null +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirNewDelegatedMemberScope.kt @@ -0,0 +1,170 @@ +/* + * Copyright 2010-2021 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.descriptors.Modality +import org.jetbrains.kotlin.descriptors.Visibilities +import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.declarations.* +import org.jetbrains.kotlin.fir.resolve.ScopeSession +import org.jetbrains.kotlin.fir.resolve.defaultType +import org.jetbrains.kotlin.fir.resolve.scope +import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor +import org.jetbrains.kotlin.fir.resolve.transformers.ensureResolved +import org.jetbrains.kotlin.fir.scopes.* +import org.jetbrains.kotlin.fir.symbols.impl.* +import org.jetbrains.kotlin.fir.types.coneType +import org.jetbrains.kotlin.name.Name + +class FirNewDelegatedMemberScope( + private val session: FirSession, + private val scopeSession: ScopeSession, + private val containingClass: FirClass<*>, + private val declaredMemberScope: FirScope, + private val delegateFields: List, +) : FirScope() { + private val dispatchReceiverType = containingClass.defaultType() + private val overrideChecker = FirStandardOverrideChecker(session) + + override fun processFunctionsByName(name: Name, processor: (FirNamedFunctionSymbol) -> Unit) { + declaredMemberScope.processFunctionsByName(name, processor) + val result = mutableListOf() + + for (delegateField in delegateFields) { + processFunctionsFromSpecificField(delegateField, name, result) + } + + result.forEach(processor) + } + + private fun buildScope(delegateField: FirField): FirTypeScope? { + delegateField.ensureResolved(FirResolvePhase.TYPES, session) + return delegateField.returnTypeRef.coneType.scope(session, scopeSession, FakeOverrideTypeCalculator.DoNothing) + } + + private fun processFunctionsFromSpecificField( + delegateField: FirField, + name: Name, + result: MutableList + ) { + val scope = buildScope(delegateField) ?: return + + scope.processFunctionsByName(name) processor@{ functionSymbol -> + val original = functionSymbol.fir + // KT-6014: If the original is abstract, we still need a delegation + // For example, + // interface IBase { override fun toString(): String } + // object BaseImpl : IBase { override fun toString(): String = ... } + // class Test : IBase by BaseImpl + if (original.isPublicInAny() && original.modality != Modality.ABSTRACT) { + return@processor + } + + if (original.modality == Modality.FINAL || original.visibility == Visibilities.Private) { + return@processor + } + + if (declaredMemberScope.getFunctions(name).any { overrideChecker.isOverriddenFunction(it.fir, original) }) { + return@processor + } + + result.firstOrNull { + overrideChecker.isOverriddenFunction(it.fir, original) + }?.let { + it.fir.multipleDelegatesWithTheSameSignature = true + return@processor + } + + val delegatedSymbol = + FirFakeOverrideGenerator.createCopyForFirFunction( + FirNamedFunctionSymbol( + functionSymbol.callableId, + ), + original, + session, + FirDeclarationOrigin.Delegated, + newDispatchReceiverType = dispatchReceiverType, + newModality = Modality.OPEN, + ).apply { + delegatedWrapperData = DelegatedWrapperData(functionSymbol.fir, containingClass.symbol.toLookupTag(), delegateField) + }.symbol + + result += delegatedSymbol + } + } + + override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) { + declaredMemberScope.processPropertiesByName(name, processor) + + val result = mutableListOf() + for (delegateField in delegateFields) { + processPropertiesFromSpecificField(delegateField, name, result) + } + + result.forEach(processor) + } + + override fun processClassifiersByNameWithSubstitution(name: Name, processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit) { + declaredMemberScope.processClassifiersByNameWithSubstitution(name, processor) + } + + override fun processDeclaredConstructors(processor: (FirConstructorSymbol) -> Unit) { + declaredMemberScope.processDeclaredConstructors(processor) + } + + private fun processPropertiesFromSpecificField( + delegateField: FirField, + name: Name, + result: MutableList + ) { + val scope = buildScope(delegateField) ?: return + + scope.processPropertiesByName(name) processor@{ propertySymbol -> + if (propertySymbol !is FirPropertySymbol) { + return@processor + } + + val original = propertySymbol.fir + + if (original.modality == Modality.FINAL || original.visibility == Visibilities.Private) { + return@processor + } + + if (declaredMemberScope.getProperties(name) + .any { it is FirPropertySymbol && overrideChecker.isOverriddenProperty(it.fir, original) } + ) { + return@processor + } + + + result.firstOrNull { + overrideChecker.isOverriddenProperty(it.fir, original) + }?.let { + it.fir.multipleDelegatesWithTheSameSignature = true + return@processor + } + + val delegatedSymbol = + FirFakeOverrideGenerator.createCopyForFirProperty( + FirPropertySymbol( + propertySymbol.callableId + ), + original, + session, + FirDeclarationOrigin.Delegated, + newModality = Modality.OPEN, + newDispatchReceiverType = dispatchReceiverType, + ).apply { + delegatedWrapperData = DelegatedWrapperData(propertySymbol.fir, containingClass.symbol.toLookupTag(), delegateField) + }.symbol + result += delegatedSymbol + } + } +} + +private object MultipleDelegatesWithTheSameSignatureKey : FirDeclarationDataKey() + +var FirCallableDeclaration<*>.multipleDelegatesWithTheSameSignature: Boolean? by FirDeclarationDataRegistry.data(MultipleDelegatesWithTheSameSignatureKey) diff --git a/compiler/testData/ir/irText/firProblems/DelegationAndInheritanceFromJava.fir.txt b/compiler/testData/ir/irText/firProblems/DelegationAndInheritanceFromJava.fir.txt index 88458a227a2..6e8058d81ce 100644 --- a/compiler/testData/ir/irText/firProblems/DelegationAndInheritanceFromJava.fir.txt +++ b/compiler/testData/ir/irText/firProblems/DelegationAndInheritanceFromJava.fir.txt @@ -8,7 +8,7 @@ FILE fqName: fileName:/DelegationAndInheritanceFromJava.kt INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:Impl modality:FINAL visibility:public superTypes:[.Foo.A; .Foo.B]' FUN DELEGATED_MEMBER name:add visibility:public modality:OPEN <> ($this:.Impl, element:@[FlexibleNullability] kotlin.String?) returnType:kotlin.Boolean overridden: - public abstract fun add (element: @[FlexibleNullability] kotlin.String?): kotlin.Boolean [fake_override] declared in .Foo.B + public abstract fun add (element: @[FlexibleNullability] kotlin.String?): kotlin.Boolean [fake_override] declared in .Foo.A $this: VALUE_PARAMETER name: type:.Impl VALUE_PARAMETER name:element index:0 type:@[FlexibleNullability] kotlin.String? BLOCK_BODY @@ -19,7 +19,7 @@ FILE fqName: fileName:/DelegationAndInheritanceFromJava.kt element: GET_VAR 'element: @[FlexibleNullability] kotlin.String? declared in .Impl.add' type=@[FlexibleNullability] kotlin.String? origin=null FUN DELEGATED_MEMBER name:addAll visibility:public modality:OPEN <> ($this:.Impl, elements:kotlin.collections.Collection<@[FlexibleNullability] kotlin.String?>) returnType:kotlin.Boolean overridden: - public abstract fun addAll (elements: kotlin.collections.Collection<@[FlexibleNullability] kotlin.String?>): kotlin.Boolean [fake_override] declared in .Foo.B + public abstract fun addAll (elements: kotlin.collections.Collection<@[FlexibleNullability] kotlin.String?>): kotlin.Boolean [fake_override] declared in .Foo.A $this: VALUE_PARAMETER name: type:.Impl VALUE_PARAMETER name:elements index:0 type:kotlin.collections.Collection<@[FlexibleNullability] kotlin.String?> BLOCK_BODY @@ -39,7 +39,7 @@ FILE fqName: fileName:/DelegationAndInheritanceFromJava.kt receiver: GET_VAR ': .Impl declared in .Impl.clear' type=.Impl origin=null FUN DELEGATED_MEMBER name:iterator visibility:public modality:OPEN <> ($this:.Impl) returnType:kotlin.collections.MutableIterator<@[FlexibleNullability] kotlin.String?> [operator] overridden: - public abstract fun iterator (): kotlin.collections.MutableIterator<@[FlexibleNullability] kotlin.String?> [fake_override,operator] declared in .Foo.B + public abstract fun iterator (): kotlin.collections.MutableIterator<@[FlexibleNullability] kotlin.String?> [fake_override,operator] declared in .Foo.A $this: VALUE_PARAMETER name: type:.Impl BLOCK_BODY RETURN type=kotlin.Nothing from='public open fun iterator (): kotlin.collections.MutableIterator<@[FlexibleNullability] kotlin.String?> [operator] declared in .Impl' @@ -48,7 +48,7 @@ FILE fqName: fileName:/DelegationAndInheritanceFromJava.kt receiver: GET_VAR ': .Impl declared in .Impl.iterator' type=.Impl origin=null FUN DELEGATED_MEMBER name:remove visibility:public modality:OPEN <> ($this:.Impl, element:@[FlexibleNullability] kotlin.String?) returnType:kotlin.Boolean overridden: - public abstract fun remove (element: @[FlexibleNullability] kotlin.String?): kotlin.Boolean [fake_override] declared in .Foo.B + public abstract fun remove (element: @[FlexibleNullability] kotlin.String?): kotlin.Boolean [fake_override] declared in .Foo.A $this: VALUE_PARAMETER name: type:.Impl VALUE_PARAMETER name:element index:0 type:@[FlexibleNullability] kotlin.String? BLOCK_BODY @@ -59,7 +59,7 @@ FILE fqName: fileName:/DelegationAndInheritanceFromJava.kt element: GET_VAR 'element: @[FlexibleNullability] kotlin.String? declared in .Impl.remove' type=@[FlexibleNullability] kotlin.String? origin=null FUN DELEGATED_MEMBER name:removeAll visibility:public modality:OPEN <> ($this:.Impl, elements:kotlin.collections.Collection<@[FlexibleNullability] kotlin.String?>) returnType:kotlin.Boolean overridden: - public abstract fun removeAll (elements: kotlin.collections.Collection<@[FlexibleNullability] kotlin.String?>): kotlin.Boolean [fake_override] declared in .Foo.B + public abstract fun removeAll (elements: kotlin.collections.Collection<@[FlexibleNullability] kotlin.String?>): kotlin.Boolean [fake_override] declared in .Foo.A $this: VALUE_PARAMETER name: type:.Impl VALUE_PARAMETER name:elements index:0 type:kotlin.collections.Collection<@[FlexibleNullability] kotlin.String?> BLOCK_BODY @@ -70,7 +70,7 @@ FILE fqName: fileName:/DelegationAndInheritanceFromJava.kt elements: GET_VAR 'elements: kotlin.collections.Collection<@[FlexibleNullability] kotlin.String?> declared in .Impl.removeAll' type=kotlin.collections.Collection<@[FlexibleNullability] kotlin.String?> origin=null FUN DELEGATED_MEMBER name:retainAll visibility:public modality:OPEN <> ($this:.Impl, elements:kotlin.collections.Collection<@[FlexibleNullability] kotlin.String?>) returnType:kotlin.Boolean overridden: - public abstract fun retainAll (elements: kotlin.collections.Collection<@[FlexibleNullability] kotlin.String?>): kotlin.Boolean [fake_override] declared in .Foo.B + public abstract fun retainAll (elements: kotlin.collections.Collection<@[FlexibleNullability] kotlin.String?>): kotlin.Boolean [fake_override] declared in .Foo.A $this: VALUE_PARAMETER name: type:.Impl VALUE_PARAMETER name:elements index:0 type:kotlin.collections.Collection<@[FlexibleNullability] kotlin.String?> BLOCK_BODY @@ -81,7 +81,7 @@ FILE fqName: fileName:/DelegationAndInheritanceFromJava.kt elements: GET_VAR 'elements: kotlin.collections.Collection<@[FlexibleNullability] kotlin.String?> declared in .Impl.retainAll' type=kotlin.collections.Collection<@[FlexibleNullability] kotlin.String?> origin=null FUN DELEGATED_MEMBER name:contains visibility:public modality:OPEN <> ($this:.Impl, element:@[FlexibleNullability] kotlin.String?) returnType:kotlin.Boolean [operator] overridden: - public abstract fun contains (element: @[FlexibleNullability] kotlin.String?): kotlin.Boolean [fake_override,operator] declared in .Foo.B + public abstract fun contains (element: @[FlexibleNullability] kotlin.String?): kotlin.Boolean [fake_override,operator] declared in .Foo.A $this: VALUE_PARAMETER name: type:.Impl VALUE_PARAMETER name:element index:0 type:@[FlexibleNullability] kotlin.String? BLOCK_BODY @@ -92,7 +92,7 @@ FILE fqName: fileName:/DelegationAndInheritanceFromJava.kt element: GET_VAR 'element: @[FlexibleNullability] kotlin.String? declared in .Impl.contains' type=@[FlexibleNullability] kotlin.String? origin=null FUN DELEGATED_MEMBER name:containsAll visibility:public modality:OPEN <> ($this:.Impl, elements:kotlin.collections.Collection<@[FlexibleNullability] kotlin.String?>) returnType:kotlin.Boolean overridden: - public abstract fun containsAll (elements: kotlin.collections.Collection<@[FlexibleNullability] kotlin.String?>): kotlin.Boolean [fake_override] declared in .Foo.B + public abstract fun containsAll (elements: kotlin.collections.Collection<@[FlexibleNullability] kotlin.String?>): kotlin.Boolean [fake_override] declared in .Foo.A $this: VALUE_PARAMETER name: type:.Impl VALUE_PARAMETER name:elements index:0 type:kotlin.collections.Collection<@[FlexibleNullability] kotlin.String?> BLOCK_BODY