[FIR] Carefully process constructors of inner and nested classes in the tower

If there is an expression receiver, we should process constructors only
  of inner classes. Constructors of nested classes can be called only
  on classifier

^KT-65333 Fixed
This commit is contained in:
Dmitriy Novozhilov
2024-02-27 12:36:29 +02:00
committed by Space Team
parent 67557ce731
commit 5b01396a11
15 changed files with 182 additions and 25 deletions
@@ -22,17 +22,23 @@ import org.jetbrains.kotlin.fir.whileAnalysing
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.deprecation.DeprecationLevelValue
private operator fun <T> Pair<T, *>?.component1() = this?.first
private operator fun <T> Pair<*, T>?.component2() = this?.second
private operator fun <T> Pair<T, *>?.component1(): T? = this?.first
private operator fun <T> Pair<*, T>?.component2(): T? = this?.second
internal fun FirScope.processConstructorsByName(
internal enum class ConstructorFilter(val acceptInner: Boolean, val acceptNested: Boolean) {
OnlyInner(acceptInner = true, acceptNested = false),
OnlyNested(acceptInner = false, acceptNested = true),
Both(acceptInner = true, acceptNested = true),
}
private fun FirScope.processConstructorsByName(
callInfo: CallInfo,
session: FirSession,
bodyResolveComponents: BodyResolveComponents,
includeInnerConstructors: Boolean,
constructorFilter: ConstructorFilter,
processor: (FirCallableSymbol<*>) -> Unit
) {
val (matchedClassifierSymbol, substitutor) = getFirstClassifierOrNull(callInfo, session, bodyResolveComponents) ?: return
val (matchedClassifierSymbol, substitutor) = getFirstClassifierOrNull(callInfo, constructorFilter, session, bodyResolveComponents) ?: return
val matchedClassSymbol = matchedClassifierSymbol as? FirClassLikeSymbol<*> ?: return
processConstructors(
@@ -41,7 +47,7 @@ internal fun FirScope.processConstructorsByName(
processor,
session,
bodyResolveComponents,
includeInnerConstructors
constructorFilter
)
processSyntheticConstructors(
@@ -55,12 +61,12 @@ internal fun FirScope.processFunctionsAndConstructorsByName(
callInfo: CallInfo,
session: FirSession,
bodyResolveComponents: BodyResolveComponents,
includeInnerConstructors: Boolean,
constructorFilter: ConstructorFilter,
processor: (FirCallableSymbol<*>) -> Unit
) {
processConstructorsByName(
callInfo, session, bodyResolveComponents,
includeInnerConstructors = includeInnerConstructors,
constructorFilter,
processor
)
@@ -116,6 +122,7 @@ private fun FirDeclaration.isInvisibleOrHidden(session: FirSession, bodyResolveC
private fun FirScope.getFirstClassifierOrNull(
callInfo: CallInfo,
constructorFilter: ConstructorFilter,
session: FirSession,
bodyResolveComponents: BodyResolveComponents
): SymbolWithSubstitutor? {
@@ -124,7 +131,14 @@ private fun FirScope.getFirstClassifierOrNull(
var result: SymbolWithSubstitutor? = null
processClassifiersByNameWithSubstitution(callInfo.name) { symbol, substitutor ->
val classifierDeclaration = symbol.fir
val isSuccessCandidate = !classifierDeclaration.isInvisibleOrHidden(session, bodyResolveComponents)
var isSuccessCandidate = !classifierDeclaration.isInvisibleOrHidden(session, bodyResolveComponents)
if (classifierDeclaration is FirClassLikeDeclaration) {
val acceptedByFilter = when (classifierDeclaration.isInner) {
true -> constructorFilter.acceptInner
false -> constructorFilter.acceptNested
}
isSuccessCandidate = isSuccessCandidate && acceptedByFilter
}
when {
isSuccessCandidate && !isSuccessResult -> {
@@ -212,7 +226,7 @@ private fun processConstructors(
processor: (FirFunctionSymbol<*>) -> Unit,
session: FirSession,
bodyResolveComponents: BodyResolveComponents,
includeInnerConstructors: Boolean
constructorFilter: ConstructorFilter
) {
whileAnalysing(session, matchedSymbol.fir) {
val scope = when (matchedSymbol) {
@@ -254,10 +268,13 @@ private fun processConstructors(
}
}
scope?.processDeclaredConstructors {
if (includeInnerConstructors || !it.fir.isInner) {
processor(it)
scope?.processDeclaredConstructors {
val shouldProcess = when (it.fir.isInner) {
true -> constructorFilter.acceptInner
false -> constructorFilter.acceptNested
}
if (shouldProcess) {
processor(it)
}
}
}
@@ -86,24 +86,31 @@ internal abstract class FirBaseTowerResolveTask(
protected fun FirScope.toScopeTowerLevel(
extensionReceiver: ReceiverValue? = null,
withHideMembersOnly: Boolean = false,
includeInnerConstructors: Boolean = extensionReceiver != null,
constructorFilter: ConstructorFilter = extensionReceiver.toConstructorFilter(),
contextReceiverGroup: ContextReceiverGroup? = null,
dispatchReceiverForStatics: ExpressionReceiverValue? = null
): ScopeTowerLevel {
return ScopeTowerLevel(
components, this,
givenExtensionReceiverOptions = createExtensionReceiverOptions(contextReceiverGroup, extensionReceiver),
withHideMembersOnly, includeInnerConstructors, dispatchReceiverForStatics
withHideMembersOnly, constructorFilter, dispatchReceiverForStatics
)
}
private fun ReceiverValue?.toConstructorFilter(): ConstructorFilter {
return when (this) {
null -> ConstructorFilter.OnlyNested
else -> ConstructorFilter.Both
}
}
protected fun FirScope.toScopeTowerLevelForStaticWithImplicitDispatchReceiver(
staticOwnerOwnerSymbol: FirRegularClassSymbol? = null,
source: KtSourceElement? = null
): ScopeTowerLevel = toScopeTowerLevel(
extensionReceiver = null,
withHideMembersOnly = false,
includeInnerConstructors = false,
constructorFilter = ConstructorFilter.OnlyNested,
contextReceiverGroup = null,
staticOwnerOwnerSymbol?.let {
val resolvedQualifier = buildResolvedQualifier {
@@ -256,7 +263,7 @@ internal open class FirTowerResolveTask(
val callableScope = qualifierReceiver.callableScope() ?: return
processLevel(
callableScope.toScopeTowerLevel(
includeInnerConstructors = false,
constructorFilter = ConstructorFilter.OnlyNested,
dispatchReceiverForStatics = when (qualifierReceiver) {
is ClassQualifierReceiver -> ExpressionReceiverValue(qualifierReceiver.explicitReceiver)
else -> null
@@ -276,7 +283,7 @@ internal open class FirTowerResolveTask(
) return
val scope = qualifierReceiver.classifierScope() ?: return
processLevel(
scope.toScopeTowerLevel(includeInnerConstructors = false), info,
scope.toScopeTowerLevel(constructorFilter = ConstructorFilter.OnlyNested), info,
TowerGroup.Classifier
)
}
@@ -280,7 +280,7 @@ class MemberScopeTowerLevel(
withMemberCallLookup(lookupTracker, info) { lookupCtx ->
this.processFunctionsAndConstructorsByName(
info, session, bodyResolveComponents,
includeInnerConstructors = true,
ConstructorFilter.OnlyInner,
processor = {
lookupCtx.recordCallableMemberLookup(it)
// WARNING, DO NOT CAST FUNCTIONAL TYPE ITSELF
@@ -370,12 +370,12 @@ class ContextReceiverGroupMemberScopeTowerLevel(
// So: dispatch receiver = strictly none (EXCEPTIONS: importing scopes with import from objects, synthetic field variable)
// So: extension receiver = either none or explicit
// (if explicit receiver exists, it always *should* be an extension receiver)
class ScopeTowerLevel(
internal class ScopeTowerLevel(
private val bodyResolveComponents: BodyResolveComponents,
val scope: FirScope,
private val givenExtensionReceiverOptions: List<FirExpression>,
private val withHideMembersOnly: Boolean,
private val includeInnerConstructors: Boolean,
private val constructorFilter: ConstructorFilter,
private val dispatchReceiverForStatics: ExpressionReceiverValue?
) : TowerScopeLevel() {
private val session: FirSession get() = bodyResolveComponents.session
@@ -486,7 +486,7 @@ class ScopeTowerLevel(
info,
session,
bodyResolveComponents,
includeInnerConstructors = includeInnerConstructors
constructorFilter
) { candidate ->
empty = false
consumeCallableCandidate(candidate, info, processor)