From 8aed6d3c4cbd214138460579a504e5b815542b93 Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Fri, 20 Jan 2023 18:07:50 +0100 Subject: [PATCH] K2: add dispatchReceiverForStatics to ScopeTowerLevel to avoid receiver hacks Related to KT-55116 --- .../kotlin/fir/resolve/calls/Candidate.kt | 4 ++ .../fir/resolve/calls/QualifierReceiver.kt | 5 +- .../tower/FirInvokeResolveTowerExtension.kt | 2 +- .../calls/tower/FirTowerResolveTask.kt | 62 ++++++++++++++----- .../fir/resolve/calls/tower/TowerLevels.kt | 61 +++++------------- .../fir/declarations/ImplicitReceiverUtils.kt | 8 ++- .../jetbrains/kotlin/fir/EnumClassUtils.kt | 4 +- ...StaticInterfaceFieldViaKotlinClass.fir.txt | 2 +- 8 files changed, 84 insertions(+), 64 deletions(-) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Candidate.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Candidate.kt index af94731ea43..e1935433007 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Candidate.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Candidate.kt @@ -27,6 +27,10 @@ import org.jetbrains.kotlin.resolve.calls.tower.isSuccess class Candidate( override val symbol: FirBasedSymbol<*>, + // Here we may have an ExpressionReceiverValue + // - in case a use-site receiver is explicit + // - in some cases with static entities, no matter is a use-site receiver explicit or not + // OR we may have here a kind of ImplicitReceiverValue (non-statics only) override var dispatchReceiverValue: ReceiverValue?, // In most cases, it contains zero or single element // More than one, only in case of context receiver group diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/QualifierReceiver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/QualifierReceiver.kt index 00aba446def..73f3e76591e 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/QualifierReceiver.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/QualifierReceiver.kt @@ -10,7 +10,6 @@ import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.declarations.FirTypeAlias import org.jetbrains.kotlin.fir.declarations.utils.expandedConeType -import org.jetbrains.kotlin.fir.expressions.FirExpression import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.resolve.toSymbol @@ -42,7 +41,9 @@ fun createQualifierReceiver( } } -abstract class QualifierReceiver(final override val explicitReceiver: FirExpression) : AbstractExplicitReceiver() { +abstract class QualifierReceiver( + final override val explicitReceiver: FirResolvedQualifier +) : AbstractExplicitReceiver() { abstract fun classifierScope(): FirScope? abstract fun callableScope(): FirScope? } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/FirInvokeResolveTowerExtension.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/FirInvokeResolveTowerExtension.kt index 8d4944f7e47..44897acc129 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/FirInvokeResolveTowerExtension.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/FirInvokeResolveTowerExtension.kt @@ -382,7 +382,7 @@ private class InvokeFunctionResolveTask( ) enumerateTowerLevels( - onScope = { scope, group -> + onScope = { scope, _, group -> processLevelForRegularInvoke( scope.toScopeTowerLevel(extensionReceiver = invokeReceiverValue), info, group, diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/FirTowerResolveTask.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/FirTowerResolveTask.kt index d180d8cd895..dda49e001bc 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/FirTowerResolveTask.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/FirTowerResolveTask.kt @@ -5,17 +5,22 @@ package org.jetbrains.kotlin.fir.resolve.calls.tower +import org.jetbrains.kotlin.KtFakeSourceElementKind +import org.jetbrains.kotlin.KtSourceElement +import org.jetbrains.kotlin.fakeElement import org.jetbrains.kotlin.fir.declarations.ContextReceiverGroup import org.jetbrains.kotlin.fir.declarations.FirTowerDataContext import org.jetbrains.kotlin.fir.expressions.FirExpression import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier import org.jetbrains.kotlin.fir.expressions.builder.buildExpressionStub -import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents -import org.jetbrains.kotlin.fir.resolve.DoubleColonLHS +import org.jetbrains.kotlin.fir.expressions.builder.buildResolvedQualifier +import org.jetbrains.kotlin.fir.resolve.* import org.jetbrains.kotlin.fir.resolve.calls.* +import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.resultType import org.jetbrains.kotlin.fir.scopes.FirScope import org.jetbrains.kotlin.fir.scopes.impl.FirWhenSubjectImportingScope +import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef import org.jetbrains.kotlin.fir.types.impl.FirImplicitBuiltinTypeRef import org.jetbrains.kotlin.fir.util.asReversedFrozen @@ -52,9 +57,6 @@ internal class TowerDataElementsForName( towerDataElement.contextReceiverGroup?.let { receiver -> IndexedValue(index, receiver) } } } - - val emptyScopes = mutableSetOf() - val implicitReceiverValuesWithEmptyScopes = mutableSetOf>() } internal abstract class FirBaseTowerResolveTask( @@ -88,10 +90,32 @@ internal abstract class FirBaseTowerResolveTask( withHideMembersOnly: Boolean = false, includeInnerConstructors: Boolean = extensionReceiver != null, contextReceiverGroup: ContextReceiverGroup? = null, + dispatchReceiverForStatics: ExpressionReceiverValue? = null ): ScopeTowerLevel = ScopeTowerLevel( components, this, givenExtensionReceiverOptions = contextReceiverGroup ?: listOfNotNull(extensionReceiver), - withHideMembersOnly, includeInnerConstructors + withHideMembersOnly, includeInnerConstructors, dispatchReceiverForStatics + ) + + protected fun FirScope.toScopeTowerLevelForStaticWithImplicitDispatchReceiver( + staticOwnerOwnerSymbol: FirRegularClassSymbol? = null, + source: KtSourceElement? = null + ): ScopeTowerLevel = toScopeTowerLevel( + extensionReceiver = null, + withHideMembersOnly = false, + includeInnerConstructors = false, + contextReceiverGroup = null, + staticOwnerOwnerSymbol?.let { + val resolvedQualifier = buildResolvedQualifier { + packageFqName = it.classId.packageFqName + relativeClassFqName = it.classId.relativeClassName + this.symbol = it + this.source = source?.fakeElement(KtFakeSourceElementKind.ImplicitReceiver) + }.apply { + resultType = components.typeForQualifier(this) + } + ExpressionReceiverValue(resolvedQualifier) + } ) protected fun ReceiverValue.toMemberScopeTowerLevel( @@ -112,12 +136,12 @@ internal abstract class FirBaseTowerResolveTask( protected inline fun enumerateTowerLevels( parentGroup: TowerGroup = TowerGroup.EmptyRoot, - onScope: (FirScope, TowerGroup) -> Unit, + onScope: (FirScope, FirRegularClassSymbol?, TowerGroup) -> Unit, onImplicitReceiver: (ImplicitReceiverValue<*>, TowerGroup) -> Unit, onContextReceiverGroup: (ContextReceiverGroup, TowerGroup) -> Unit, ) { for ((index, localScope) in towerDataElementsForName.reversedFilteredLocalScopes) { - onScope(localScope, parentGroup.Local(index)) + onScope(localScope, null, parentGroup.Local(index)) } for ((depth, lexical) in towerDataElementsForName.nonLocalTowerDataElements.withIndex()) { @@ -125,6 +149,7 @@ internal abstract class FirBaseTowerResolveTask( if (!lexical.isLocal && scope != null) { onScope( scope, + lexical.staticScopeOwnerSymbol, if (scope is FirWhenSubjectImportingScope) TowerGroup.UnqualifiedEnum(depth) else parentGroup.NonLocal(depth) ) @@ -220,7 +245,13 @@ internal open class FirTowerResolveTask( if (qualifierReceiver == null) return val callableScope = qualifierReceiver.callableScope() ?: return processLevel( - callableScope.toScopeTowerLevel(includeInnerConstructors = false), + callableScope.toScopeTowerLevel( + includeInnerConstructors = false, + dispatchReceiverForStatics = when (qualifierReceiver) { + is ClassQualifierReceiver -> ExpressionReceiverValue(qualifierReceiver.explicitReceiver) + else -> null + } + ), info, TowerGroup.Qualifier ) } @@ -256,7 +287,7 @@ internal open class FirTowerResolveTask( enumerateTowerLevels( parentGroup = parentGroup, - onScope = { scope, group -> + onScope = { scope, _, group -> processScopeForExplicitReceiver( scope, explicitReceiverValue, @@ -289,13 +320,16 @@ internal open class FirTowerResolveTask( val implicitReceiverValuesWithEmptyScopes = mutableSetOf>() enumerateTowerLevels( - onScope = l@{ scope, group -> + onScope = l@{ scope, staticScopeOwnerSymbol, group -> // NB: this check does not work for variables // because we do not search for objects if we have extension receiver if (info.callKind != CallKind.VariableAccess && scope in emptyScopes) return@l processLevel( - scope.toScopeTowerLevel(), info, group, + scope.toScopeTowerLevelForStaticWithImplicitDispatchReceiver( + staticScopeOwnerSymbol, source = info.callSite.source + ), + info, group, onEmptyLevel = { emptyScopes += scope } @@ -386,7 +420,7 @@ internal open class FirTowerResolveTask( enumerateTowerLevels( parentGroup, - onScope = l@{ scope, group -> + onScope = l@{ scope, _, group -> if (scope in emptyScopes) return@l processLevel( @@ -425,7 +459,7 @@ internal open class FirTowerResolveTask( enumerateTowerLevels( parentGroup, - onScope = { scope, towerGroup -> + onScope = { scope, _, towerGroup -> processLevel( scope.toScopeTowerLevel(contextReceiverGroup = contextReceiverGroup), info, towerGroup, diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/TowerLevels.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/TowerLevels.kt index 6546478f4cd..651d125718b 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/TowerLevels.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/TowerLevels.kt @@ -7,7 +7,6 @@ package org.jetbrains.kotlin.fir.resolve.calls.tower import org.jetbrains.kotlin.KtFakeSourceElementKind import org.jetbrains.kotlin.KtSourceElement -import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.fakeElement import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.declarations.ContextReceiverGroup @@ -15,7 +14,6 @@ import org.jetbrains.kotlin.fir.declarations.FirConstructor import org.jetbrains.kotlin.fir.declarations.getAnnotationByClassId import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.utils.isInner -import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier import org.jetbrains.kotlin.fir.expressions.FirSmartCastExpression import org.jetbrains.kotlin.fir.expressions.builder.buildResolvedQualifier import org.jetbrains.kotlin.fir.resolve.* @@ -326,7 +324,8 @@ class ScopeTowerLevel( val scope: FirScope, private val givenExtensionReceiverOptions: List, private val withHideMembersOnly: Boolean, - private val includeInnerConstructors: Boolean + private val includeInnerConstructors: Boolean, + private val dispatchReceiverForStatics: ExpressionReceiverValue? ) : TowerScopeLevel() { private val session: FirSession get() = bodyResolveComponents.session @@ -344,22 +343,7 @@ class ScopeTowerLevel( return ExpressionReceiverValue(resolvedQualifier) } - private fun FirRegularClassSymbol.findJavaSuperClassSymbol(): FirRegularClassSymbol? { - var currentSymbol = this - while (currentSymbol.origin !is FirDeclarationOrigin.Java) { - var baseClassSymbol: FirRegularClassSymbol? = null - for (superType in currentSymbol.resolvedSuperTypes) { - val symbol = superType.fullyExpandedType(session).toSymbol(session) - if (symbol is FirRegularClassSymbol && symbol.classKind == ClassKind.CLASS) { - baseClassSymbol = symbol - break - } - } - currentSymbol = baseClassSymbol ?: return null - } - return currentSymbol - } - + // For static entries we may return here FirResolvedQualifier, wrapped in ExpressionReceiverValue private fun dispatchReceiverValue(candidate: FirCallableSymbol<*>, callInfo: CallInfo): ReceiverValue? { candidate.fir.importedFromObjectOrStaticData?.let { data -> val objectClassId = data.objectClassId @@ -369,36 +353,25 @@ class ScopeTowerLevel( } } - if (candidate is FirBackingFieldSymbol) { - val lookupTag = candidate.fir.propertySymbol.dispatchReceiverClassLookupTagOrNull() - return when { - lookupTag != null -> { - bodyResolveComponents.implicitReceiverStack.lastDispatchReceiver { implicitReceiverValue -> - (implicitReceiverValue.type as? ConeClassLikeType)?.fullyExpandedType(session)?.lookupTag == lookupTag + when { + candidate is FirBackingFieldSymbol -> { + val lookupTag = candidate.fir.propertySymbol.dispatchReceiverClassLookupTagOrNull() + return when { + lookupTag != null -> { + bodyResolveComponents.implicitReceiverStack.lastDispatchReceiver { implicitReceiverValue -> + (implicitReceiverValue.type as? ConeClassLikeType)?.fullyExpandedType(session)?.lookupTag == lookupTag + } + } + else -> { + bodyResolveComponents.implicitReceiverStack.lastDispatchReceiver() } } - - else -> { - bodyResolveComponents.implicitReceiverStack.lastDispatchReceiver() - } } - } - if (candidate.isStatic && candidate.isJavaOrEnhancement) { - val explicitReceiver = callInfo.explicitReceiver - if (explicitReceiver is FirResolvedQualifier) { - return ExpressionReceiverValue(explicitReceiver) + candidate.isStatic -> { + return dispatchReceiverForStatics } - val lookupTag = candidate.fir.containingClassLookupTag() ?: return null - val implicitDispatchReceiverValue = bodyResolveComponents.implicitReceiverStack.lastDispatchReceiver { implicitReceiverValue -> - implicitReceiverValue is ImplicitDispatchReceiverValue && implicitReceiverValue.boundSymbol.fir.isSubclassOf( - lookupTag, session, isStrict = false, lookupInterfaces = false - ) - } ?: return null - // Note: we know that candidate is from Java, so normally we should find this class and its Java superclass - val regularClassSymbol = implicitDispatchReceiverValue.boundSymbol as? FirRegularClassSymbol ?: return null - return regularClassSymbol.findJavaSuperClassSymbol()?.toResolvedQualifierExpressionReceiver(callInfo.callSite.source) + else -> return null } - return null } private fun shouldSkipCandidateWithInconsistentExtensionReceiver(candidate: FirCallableSymbol<*>): Boolean { diff --git a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/declarations/ImplicitReceiverUtils.kt b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/declarations/ImplicitReceiverUtils.kt index 2010b0f293b..fcee6805914 100644 --- a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/declarations/ImplicitReceiverUtils.kt +++ b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/declarations/ImplicitReceiverUtils.kt @@ -16,6 +16,7 @@ import org.jetbrains.kotlin.fir.scopes.FirContainingNamesAwareScope import org.jetbrains.kotlin.fir.scopes.FirScope import org.jetbrains.kotlin.fir.scopes.impl.FirLocalScope import org.jetbrains.kotlin.fir.scopes.impl.wrapNestedClassifierScopeWithSubstitutionForSuperType +import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol import org.jetbrains.kotlin.fir.types.ConeKotlinType import org.jetbrains.kotlin.fir.types.coneType import org.jetbrains.kotlin.name.Name @@ -78,7 +79,7 @@ fun SessionHolder.collectTowerDataElementsForClass(owner: FirClass, defaultType: superClass.staticScope(this) ?.wrapNestedClassifierScopeWithSubstitutionForSuperType(expandedType, session) - ?.asTowerDataElement(isLocal = false) + ?.asTowerDataElementForStaticScope(staticScopeOwnerSymbol = superClass.symbol) ?.let(superClassesStaticsAndCompanionReceivers::add) (superClass as? FirRegularClass)?.companionObjectSymbol?.let { @@ -223,6 +224,7 @@ class FirTowerDataElement( val implicitReceiver: ImplicitReceiverValue<*>?, val contextReceiverGroup: ContextReceiverGroup? = null, val isLocal: Boolean, + val staticScopeOwnerSymbol: FirRegularClassSymbol? = null ) { fun createSnapshot(): FirTowerDataElement = FirTowerDataElement( @@ -230,6 +232,7 @@ class FirTowerDataElement( implicitReceiver?.createSnapshot(), contextReceiverGroup?.map { it.createSnapshot() }, isLocal, + staticScopeOwnerSymbol ) } @@ -242,6 +245,9 @@ fun ContextReceiverGroup.asTowerDataElement(): FirTowerDataElement = fun FirScope.asTowerDataElement(isLocal: Boolean): FirTowerDataElement = FirTowerDataElement(scope = this, implicitReceiver = null, isLocal = isLocal) +fun FirScope.asTowerDataElementForStaticScope(staticScopeOwnerSymbol: FirRegularClassSymbol?): FirTowerDataElement = + FirTowerDataElement(scope = this, implicitReceiver = null, isLocal = false, staticScopeOwnerSymbol = staticScopeOwnerSymbol) + fun FirClass.staticScope(sessionHolder: SessionHolder): FirContainingNamesAwareScope? = staticScope(sessionHolder.session, sessionHolder.scopeSession) diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/EnumClassUtils.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/EnumClassUtils.kt index f7112175688..f44e00fcf91 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/EnumClassUtils.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/EnumClassUtils.kt @@ -150,7 +150,9 @@ fun FirRegularClassBuilder.generateEntriesGetter( moduleData, FirDeclarationOrigin.Source, returnTypeRef.copyWithNewSourceKind(KtFakeSourceElementKind.EnumGeneratedDeclaration), Visibilities.Public, symbol ).apply { - (status as FirDeclarationStatusImpl).isStatic = true + this.status = createStatus(this@generateEntriesGetter.status).apply { + isStatic = true + } } }.apply { containingClassForStaticMemberAttr = this@generateEntriesGetter.symbol.toLookupTag() diff --git a/compiler/testData/diagnostics/tests/visibility/packagePrivateStaticInterfaceFieldViaKotlinClass.fir.txt b/compiler/testData/diagnostics/tests/visibility/packagePrivateStaticInterfaceFieldViaKotlinClass.fir.txt index 561de3be00c..4db48b55ed9 100644 --- a/compiler/testData/diagnostics/tests/visibility/packagePrivateStaticInterfaceFieldViaKotlinClass.fir.txt +++ b/compiler/testData/diagnostics/tests/visibility/packagePrivateStaticInterfaceFieldViaKotlinClass.fir.txt @@ -14,7 +14,7 @@ FILE: Child.kt } public final fun foo(): R|kotlin/Unit| { - lval x: R|kotlin/String| = R|javapackage/PackagePrivateGrandparentInterface.publicStaticField| + lval x: R|kotlin/String| = Q|javapackage/PublicParentClass|.R|javapackage/PackagePrivateGrandparentInterface.publicStaticField| lval y: R|kotlin/String| = Q|javapackage/PublicParentClass|.R|javapackage/PackagePrivateGrandparentInterface.publicStaticField| lval z: = Q|javapackage/KotlinParentClass|.# }