K2: add dispatchReceiverForStatics to ScopeTowerLevel to avoid receiver hacks
Related to KT-55116
This commit is contained in:
committed by
Space Team
parent
d436d56871
commit
8aed6d3c4c
@@ -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
|
||||
|
||||
+3
-2
@@ -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<FirResolvedQualifier>() {
|
||||
abstract class QualifierReceiver(
|
||||
final override val explicitReceiver: FirResolvedQualifier
|
||||
) : AbstractExplicitReceiver<FirResolvedQualifier>() {
|
||||
abstract fun classifierScope(): FirScope?
|
||||
abstract fun callableScope(): FirScope?
|
||||
}
|
||||
|
||||
+1
-1
@@ -382,7 +382,7 @@ private class InvokeFunctionResolveTask(
|
||||
)
|
||||
|
||||
enumerateTowerLevels(
|
||||
onScope = { scope, group ->
|
||||
onScope = { scope, _, group ->
|
||||
processLevelForRegularInvoke(
|
||||
scope.toScopeTowerLevel(extensionReceiver = invokeReceiverValue),
|
||||
info, group,
|
||||
|
||||
+48
-14
@@ -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<FirScope>()
|
||||
val implicitReceiverValuesWithEmptyScopes = mutableSetOf<ImplicitReceiverValue<*>>()
|
||||
}
|
||||
|
||||
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<ImplicitReceiverValue<*>>()
|
||||
|
||||
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,
|
||||
|
||||
+17
-44
@@ -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<ReceiverValue>,
|
||||
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 {
|
||||
|
||||
+7
-1
@@ -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)
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
+1
-1
@@ -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: <ERROR TYPE REF: Unresolved name: publicStaticField> = Q|javapackage/KotlinParentClass|.<Unresolved name: publicStaticField>#
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user