diff --git a/compiler/fir/analysis-tests/testData/resolve/diagnostics/superCallWithDelegation.kt b/compiler/fir/analysis-tests/testData/resolve/diagnostics/superCallWithDelegation.kt index 738ae9e1bd5..3b434d4f2f4 100644 --- a/compiler/fir/analysis-tests/testData/resolve/diagnostics/superCallWithDelegation.kt +++ b/compiler/fir/analysis-tests/testData/resolve/diagnostics/superCallWithDelegation.kt @@ -7,6 +7,6 @@ open class B(private val a: A) : A by a class C(a: A) : B(a) { override fun foo() { // Should be resolved to delegated B.foo (no error) - super.foo() + super.foo() } } \ No newline at end of file diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConstructorProcessing.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConstructorProcessing.kt index c9b0ff59365..7123567e327 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConstructorProcessing.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConstructorProcessing.kt @@ -164,7 +164,7 @@ private fun processConstructors( } is FirClassSymbol -> (matchedSymbol.fir as FirClass<*>).scope( - substitutor, session, scopeSession, false, + substitutor, session, scopeSession, skipPrivateMembers = false, ) } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/KotlinScopeProvider.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/KotlinScopeProvider.kt index 049e52258a3..845991bba98 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/KotlinScopeProvider.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/KotlinScopeProvider.kt @@ -7,18 +7,17 @@ package org.jetbrains.kotlin.fir.scopes import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.fir.FirSession -import org.jetbrains.kotlin.fir.declarations.FirClass -import org.jetbrains.kotlin.fir.declarations.FirRegularClass -import org.jetbrains.kotlin.fir.declarations.classId -import org.jetbrains.kotlin.fir.declarations.isExpect +import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.resolve.* import org.jetbrains.kotlin.fir.resolve.toSymbol import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap import org.jetbrains.kotlin.fir.scopes.impl.* +import org.jetbrains.kotlin.fir.symbols.CallableId import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol import org.jetbrains.kotlin.fir.types.ConeClassErrorType import org.jetbrains.kotlin.fir.types.ConeClassLikeType +import org.jetbrains.kotlin.fir.types.coneType import org.jetbrains.kotlin.name.ClassId class KotlinScopeProvider( @@ -39,14 +38,16 @@ class KotlinScopeProvider( val decoratedDeclaredMemberScope = declaredMemberScopeDecorator(klass, declaredScope, useSiteSession, scopeSession) + val delegateFields = klass.declarations.filterIsInstance().filter { it.isSynthetic } val scopes = lookupSuperTypes(klass, lookupInterfaces = true, deep = false, useSiteSession = useSiteSession) .mapNotNull { useSiteSuperType -> if (useSiteSuperType is ConeClassErrorType) return@mapNotNull null val symbol = useSiteSuperType.lookupTag.toSymbol(useSiteSession) if (symbol is FirRegularClassSymbol) { + val delegateField = delegateFields.find { it.returnTypeRef.coneType == useSiteSuperType } symbol.fir.scope( substitutor(symbol, useSiteSuperType, useSiteSession), - useSiteSession, scopeSession, + useSiteSession, scopeSession, delegateField, skipPrivateMembers = true, classId = klass.classId, isFromExpectClass = (klass as? FirRegularClass)?.isExpect == true @@ -94,6 +95,8 @@ data class ConeSubstitutionScopeKey( val classId: ClassId?, val isFromExpectClass: Boolean, val substitutor: ConeSubstitutor ) : ScopeSessionKey, FirClassSubstitutionScope>() +data class DelegatedMemberScopeKey(val callableId: CallableId) : ScopeSessionKey() + fun FirClass<*>.unsubstitutedScope(useSiteSession: FirSession, scopeSession: ScopeSession): FirTypeScope { return scopeProvider.getUseSiteMemberScope(this, useSiteSession, scopeSession) } @@ -102,13 +105,20 @@ internal fun FirClass<*>.scope( substitutor: ConeSubstitutor, useSiteSession: FirSession, scopeSession: ScopeSession, + delegateField: FirField? = null, skipPrivateMembers: Boolean, classId: ClassId? = this.classId, isFromExpectClass: Boolean = false ): FirTypeScope { - val basicScope = scopeProvider.getUseSiteMemberScope( - this, useSiteSession, scopeSession - ) + val basicScope = unsubstitutedScope(useSiteSession, scopeSession).let { + if (delegateField != null) { + scopeSession.getOrBuild(delegateField, DelegatedMemberScopeKey(delegateField.symbol.callableId)) { + FirDelegatedMemberScope(it, useSiteSession) + } + } else { + it + } + } if (substitutor == ConeSubstitutor.Empty) return basicScope return scopeSession.getOrBuild( diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirDelegatedMemberScope.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirDelegatedMemberScope.kt new file mode 100644 index 00000000000..d1588d85df6 --- /dev/null +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirDelegatedMemberScope.kt @@ -0,0 +1,121 @@ +/* + * Copyright 2010-2020 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.fir.FirSession +import org.jetbrains.kotlin.fir.declarations.* +import org.jetbrains.kotlin.fir.declarations.builder.buildProperty +import org.jetbrains.kotlin.fir.declarations.builder.buildSimpleFunction +import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl +import org.jetbrains.kotlin.fir.scopes.FirTypeScope +import org.jetbrains.kotlin.fir.scopes.ProcessorAction +import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol +import org.jetbrains.kotlin.name.Name + +class FirDelegatedMemberScope( + private val useSiteScope: FirTypeScope, + private val session: FirSession +) : FirTypeScope() { + private val delegatedFunctionCache = mutableMapOf() + private val delegatedPropertyCache = mutableMapOf() + + override fun processFunctionsByName(name: Name, processor: (FirFunctionSymbol<*>) -> Unit) { + useSiteScope.processFunctionsByName(name) processor@{ functionSymbol -> + if (functionSymbol !is FirNamedFunctionSymbol) { + processor(functionSymbol) + return@processor + } + val original = functionSymbol.fir + if (original.modality == Modality.FINAL) { + processor(functionSymbol) + return@processor + } + val delegatedSymbol = delegatedFunctionCache.getOrPut(functionSymbol) { + val delegatedFunction = buildSimpleFunction { + origin = FirDeclarationOrigin.Delegated + session = this@FirDelegatedMemberScope.session + this.name = name + symbol = FirNamedFunctionSymbol( + functionSymbol.callableId, + overriddenSymbol = functionSymbol + ) + status = FirDeclarationStatusImpl(original.visibility, Modality.OPEN).apply { + isOperator = original.isOperator + } + resolvePhase = FirResolvePhase.BODY_RESOLVE + returnTypeRef = original.returnTypeRef + receiverTypeRef = original.receiverTypeRef + valueParameters.addAll(original.valueParameters) + typeParameters.addAll(original.typeParameters) + annotations.addAll(original.annotations) + } + delegatedFunction.symbol as FirNamedFunctionSymbol + } + processor(delegatedSymbol) + } + } + + override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) { + useSiteScope.processPropertiesByName(name) processor@{ propertySymbol -> + if (propertySymbol !is FirPropertySymbol) { + processor(propertySymbol) + return@processor + } + val original = propertySymbol.fir + if (original.modality == Modality.FINAL) { + processor(propertySymbol) + return@processor + } + val delegatedSymbol = delegatedPropertyCache.getOrPut(propertySymbol) { + val delegatedProperty = buildProperty { + origin = FirDeclarationOrigin.Delegated + session = this@FirDelegatedMemberScope.session + this.name = name + symbol = FirPropertySymbol( + propertySymbol.callableId, + overriddenSymbol = propertySymbol + ) + isVar = original.isVar + isLocal = false + status = FirDeclarationStatusImpl(original.visibility, Modality.OPEN) + resolvePhase = FirResolvePhase.BODY_RESOLVE + returnTypeRef = original.returnTypeRef + receiverTypeRef = original.receiverTypeRef + typeParameters.addAll(original.typeParameters) + annotations.addAll(original.annotations) + } + delegatedProperty.symbol + } + processor(delegatedSymbol) + } + } + + override fun processDirectOverriddenFunctionsWithBaseScope( + functionSymbol: FirFunctionSymbol<*>, + processor: (FirFunctionSymbol<*>, FirTypeScope) -> ProcessorAction + ): ProcessorAction { + return useSiteScope.processDirectOverriddenFunctionsWithBaseScope(functionSymbol, processor) + } + + override fun processDirectOverriddenPropertiesWithBaseScope( + propertySymbol: FirPropertySymbol, + processor: (FirPropertySymbol, FirTypeScope) -> ProcessorAction + ): ProcessorAction { + return useSiteScope.processDirectOverriddenPropertiesWithBaseScope(propertySymbol, processor) + } + + override fun getCallableNames(): Set { + return useSiteScope.getCallableNames() + } + + override fun getClassifierNames(): Set { + return useSiteScope.getClassifierNames() + } +} \ No newline at end of file diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirDeclarationOrigin.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirDeclarationOrigin.kt index bf5189b0d54..79b2af8c730 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirDeclarationOrigin.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirDeclarationOrigin.kt @@ -15,6 +15,7 @@ sealed class FirDeclarationOrigin { object Enhancement : FirDeclarationOrigin() object ImportedFromObject : FirDeclarationOrigin() object IntersectionOverride : FirDeclarationOrigin() + object Delegated : FirDeclarationOrigin() class Plugin(val key: FirPluginKey) : FirDeclarationOrigin() }